簡體   English   中英

如何提高此 CopyTo 方法的性能?

[英]How can I improve the performance of this CopyTo method?

編輯:我現在已經解決了這個問題。 我的答案發布在下面,當 SO 允許我時將標記為已解決。

我有一個 CopyTo(和一個 CopyToAsync)方法來復制 C# 應用程序中的文件。 我發現與 Xcopy 之類的東西相比,復制文件實際上很慢。

我提取了 copy 方法的核心功能並將其放入測試控制台應用程序中,以獲得它與 Xcopy 相比的運行速度,發現結果實際上完全不同。

我得到的結果是:

異步方法:36.59 秒 - 平均速度:1512.63 mb/sec

同步方法:36.49 秒 - 平均速度:1516.72 mb/sec

XCOPY:5.62 秒 - 平均速度:9842.11 mb/sec

這三個都使用完全相同的文件和完全相同的目的地。

流擴展 class:

public static class StreamExtensions
    {

        const int DEFAULT_BUFFER = 0x1000; // 4096 bits

        public static async Task CopyToAsync(this Stream source, Stream destination, IProgress<long> progress, CancellationToken cancellationToken = default, int bufferSize = DEFAULT_BUFFER)
        {
            var buffer = new byte[bufferSize];
            int bytesRead;
            long totalRead = 0;

            while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken)) > 0)
            {
                await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken);

                cancellationToken.ThrowIfCancellationRequested();

                totalRead += bytesRead;
                progress.Report(totalRead);
            }
        }

        public static void CopyTo(this Stream source, Stream destination, IProgress<long> progress, int bufferSize = DEFAULT_BUFFER)
        {
            var buffer = new byte[bufferSize];
            int bytesRead;
            long totalRead = 0;

            while ((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0)
            {
                destination.Write(buffer, 0, bytesRead);

                totalRead += bytesRead;
                progress.Report(totalRead);
            }
        }
    }

IProgress<long> object 是將文件進度報告回調用方法。

示例調用實現:

// Asynchronous version
public static async Task CopyFileSetAsync(Dictionary<string, string> fileSet)
{
    for (var x = 0; x < fileSet.Count; x++)
    {
        var item = fileSet.ElementAt(x);
        var from = item.Key;
        var to = item.Value;

        int currentProgress = 0;

        long fileSize = new FileInfo(from).Length;

        IProgress<long> progress = new SynchronousProgress<long>(value =>
        {
            decimal fileProg = (decimal)(value * 100) / fileSize;

            if (fileProg != currentProgress)
            {
                currentProgress = (int)fileProg;
                OnUpdateFileProgress(null, new FileProgressEventArgs(fileProg));
            }
        });

        using (var outStream = new FileStream(to, FileMode.Create, FileAccess.Write, FileShare.Read))
        {
            using (var inStream = new FileStream(from, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                await inStream.CopyToAsync(outStream, progress);
            }
        }

        OnUpdateFileProgress(null, new FileProgressEventArgs(100)); // Probably redundant
    }
}

// Synchronous version
public static void CopyFileSet(Dictionary<string, string> fileSet)
{
    for (var x = 0; x < fileSet.Count; x++)
    {
        var item = fileSet.ElementAt(x);
        var from = item.Key;
        var to = item.Value;

        int currentProgress = 0;

        long fileSize = new FileInfo(from).Length;

        IProgress<long> progress = new SynchronousProgress<long>(value =>
        {
            decimal fileProg = (decimal)(value * 100) / fileSize;

            if (fileProg != currentProgress)
            {
                currentProgress = (int)fileProg;
                OnUpdateFileProgress(null, new FileProgressEventArgs(fileProg));
            }
        });

        using (var outStream = new FileStream(to, FileMode.Create, FileAccess.Write, FileShare.Read))
        {
            using (var inStream = new FileStream(from, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                inStream.CopyTo(outStream, progress, 1024);
            }
        }

        OnUpdateFileProgress(null, new FileProgressEventArgs(100)); // Probably redundant
    }
}

有什么東西可以阻止它盡可能快地運行嗎? 我只是對它與復制相比慢了多少感到困惑。

編輯:修正了一個錯字,我在 IProgress 周圍忘記了一個 `

感謝Tomxanatos ,我回答了我自己的問題:

我誤解了緩沖區大小的影響。 我只達到了 8192 字節作為緩沖區大小。 在接受了他們的建議后,我將緩沖區大小增加到 1mb(1048576 字節),這對性能產生了巨大的影響。

異步方法:5.57 秒 - 平均速度:9938.68 mb/sec

同步方法:5.52 秒 - 平均速度:10028.36 mb/sec

XCOPY:5.03 秒 - 平均速度:11007.84 mb/sec

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM