c# - 跟踪并行 Foreach 线程

标签 c# wpf multithreading parallel-processing

我目前正在编写一个简单的 WPF 文件复制应用程序,它可以并行复制文件。到目前为止效果很好!它做我想让它做的一切。该操作的主要内容在以下代码块中:

Parallel.ForEach(Directory.GetFiles(dir).ToList(), file =>
{
    _destDetail.CurrOp = string.Format("Copying file: {0}", Path.GetFileName(file));
    File.Copy(file, file.Replace(_destDetail.Source, _destDetail.Dest), true);
    if (_destDetail.Progress < _destDetail.MaxProgress)
        _destDetail.Progress++;
});

我可以实现 ParallelOptions 并将最大线程数也限制为 4,但我想知道是否有一种方法可以准确地跟踪每个线程在这种情况下会做什么?

例如,假设我的 UI 中有一部分专门用于复制操作的当前“状态”。我想在一个 Grid 中有 4 行,每行都有一个特定的线程以及它当前正在复制的文件。

我知道我可以使用 Interlocked 来操作 Parallel 循环之外的变量,但是我如何从内部跟踪特定于线程的变量 Parallel 循环并使用这些变量使 UI 保持最新,了解哪个线程正在处理哪个文件?

最佳答案

不是直接跟踪线程,而是让 UI 绑定(bind)到 ObserveableCollection<ProgressDetail>每个代表进度,然后在您的循环中让它在开始时向集合中添加一个项目,然后在结束时将其从集合中删除。

您必须注意的一件事是线程安全,ObseveableCollection不是线程安全的,因此您必须仅以线程安全的方式与它交互,最简单的方法是对 ProgressDetail 进行所有添加和删除操作。 UI线程上的对象。这还有一个额外的好处,即在创建 Progress 时捕获 UI 线程的 SynchronizationContext。对象。

public ObserveableCollection<ProgressDetail> ProgressCollection {get; private set;}

public void CopyFiles(string dir)
{

    var dispatcher = Application.Current.Dispatcher;
    Parallel.ForEach(Directory.GetFiles(dir).ToList(), file =>
    {
        ProgressDetail progressDetail = null;
        dispatcher.Invoke(() => 
        {
           // We make the `Progress` object on the UI thread so it can capture the  
           // SynchronizationContext during its construction.
           progressDetail = new ProgressDetail(file);
           ProgressCollection.Add(progressDetail);
        }

        XCopy.Copy(file, file.Replace(_destDetail.Source, _destDetail.Dest), 
                   true, false, progressDetail.ProgressReporter);

        dispatcher.Invoke(() => ProgressCollection.Remove(progressDetail);
    });

}

public sealed class ProgressDetail : INotifyPropertyChanged
{
    private double _progressPercentage;

    public ProgressDetail(string fileName)
    {
        FileName = fileName;
        ProgressReporter = new Progress<double>(OnProgressReported);
    }

    public string FileName { get; private set; }
    public IProgress<double> ProgressReporter { get; private set; }
    public double ProgressPercentage
    {
        get { return _progressPercentage; }
        private set
        {
            if (value.Equals(_progressPercentage)) return;
            _progressPercentage = value;
            OnPropertyChanged();
        }
    }

    private void OnProgressReported(double progress)
    {
        ProgressPercentage = progress;
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var temp = PropertyChanged;
        if(temp != null)
            temp(this, new PropertyChangedEventArgs(propertyName));
    }
}

参见 this answer例如 XCopy会随着进度复制的类。我假设 Copy 的签名已更改为

public static void Copy(string source, string destination, bool overwrite, bool nobuffering, IProgress<double> handler)

但我将实际更改留给读者作为练习。

更新:我更新了上面的代码示例以公开一个公共(public)属性 ProgressPercentage它可以绑定(bind)并引发适当的事件。我也动听了Progress的事件进入 ProgressDetail 的内部类。

关于c# - 跟踪并行 Foreach 线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32701537/

相关文章:

c# - 属性 getter/setter 的方法命名是否在 IL 中标准化?

c# - 如何更改项目中的启动窗体?

C# MEF : Exporting multiple objects of one type, 和导入特定的

Java线程: how do threads return values

multithreading - 如何在Rust中的线程之间共享不可变数据?

java多线程和对象

c# - 如何设计炫酷的半透明闪屏?

c# - 使用套接字通过代理将请求从客户端中继到服务器 C#

wpf - 如何将关闭命令绑定(bind)到按钮

wpf - Graphics.CopyFromScreen 有时会捕获透明窗口,有时不会