c# Parallel.For 和 UI 更新?

标签 c# winforms user-interface parallel-processing

我正在尝试实现一个 Parallel.ForEach 循环来替换旧的 foreach 循环,但是我在更新我的 UI 时遇到了问题(我有一个计数器显示类似“x/y 文件已处理”的内容).我制作了一个并行 Forloop 示例来说明我的问题(标签未更新)。

using System;
using System.Windows.Forms;
using System.Threading.Tasks;
using System.Threading;

namespace FormThreadTest
{
    public partial class Form1 : Form
    {
        private SynchronizationContext m_sync;
        private System.Timers.Timer m_timer;
        private int m_count;

        public Form1()
        {                       
            InitializeComponent();

            m_sync = SynchronizationContext.Current;

            m_count = 0;

            m_timer = new System.Timers.Timer();
            m_timer.Interval = 1000;
            m_timer.AutoReset = true;
            m_timer.Elapsed += new System.Timers.ElapsedEventHandler(m_timer_Elapsed);
            m_timer.Start();
        }

        private void m_timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            Task.Factory.StartNew(() =>
            {
                m_sync.Post((o) =>
                {
                    label1.Text = m_count.ToString();
                    Application.DoEvents();
                }, null);
            });
        }

        private void button1_Click(object sender, EventArgs e)        
        {     
            Task.Factory.StartNew(() =>
            {
                Parallel.For(0, 25000000, delegate(int i)
                {
                    m_count = i;
                });
            });
        }
    }
}

如果我更改按钮单击事件方法,并添加一个 Thread.Sleep(),它似乎为 UI 更新线程提供了时间来完成它的工作:

private void button1_Click(object sender, EventArgs e)        
        {     
            Task.Factory.StartNew(() =>
            {
                Parallel.For(0, 25000000, delegate(int i)
                {
                    m_count = i;
                    Thread.Sleep(10);
                });
            });
        }

有没有办法避免 sleep ,还是我需要在那里 sleep ?除非我这样做,否则我的用户界面似乎不会更新标签?我觉得很奇怪,因为我可以移动应用程序窗口(它不会锁定)——那么为什么标签不更新,我怎样才能改变我的代码以更好地支持 Parallel.For(Each) 和 UI 更新?

我一直在寻找解决方案,但我似乎找不到任何东西(或者我可能在寻找错误的东西?)。

问候 西蒙

最佳答案

我有类似的要求来更新我的 GUI,因为结果来自 Parallel.ForEach()。不过,我走的路和你走的路很不一样。

public partial class ClassThatUsesParallelProcessing
{
    public event ProcessingStatusEvent StatusEvent;

    public ClassThatUsesParallelProcessing()
    { }

    private void doSomethingInParallel()
    {
        try
        {
            int counter = 0;
            int total = listOfItems.Count;

            Parallel.ForEach(listOfItems, (instanceFromList, state) =>
            {
                // do your work here ...

                // determine your progress and fire event back to anyone who cares ...
                int count = Interlocked.Increment( ref counter );

                int percentageComplete = (int)((float)count / (float)total * 100);
                OnStatusEvent(new StatusEventArgs(State.UPDATE_PROGRESS, percentageComplete));
            }
        }
        catch (Exception ex)
        {

        }
    }
}

然后您的 GUI 将具有类似于以下内容的内容:

private void ProcessingStatusEventHandler(object sender, StatusEventArgs e)
{
    try
    {
        if (e.State.Value == State.UPDATE_PROGRESS)
        {
            this.BeginInvoke((ProcessHelperDelegate)delegate
            {
                this.progressBar.Value = e.PercentageComplete;
            }
        }
    }
    catch { }
}

我在这里想说明的唯一一点是,您可以确定何时确定您在循环中的进度是有意义的。而且,由于这些循环迭代是在后台线程上进行的,因此您需要将 GUI 控件更新逻辑编码回主(调度)线程。这只是一个简单的示例 - 只要确保您遵循这个概念就可以了。

关于c# Parallel.For 和 UI 更新?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4783109/

相关文章:

c# - SqlDataReader 这两个是一样的哪个更快

c# - 将字符串转换为字节数组

使用 .Equals() 而不是散列的 C# 字典

c# - 如何将字节数组转换为字符串?

java - 在 JScrollPane 中查找可见组件的快速方法

c# - 如何在 C# 控制台中突出显示和选择控制台文本

c# - 如何通过 UnhandledException 卸载 AppDomain

c# - 从另一个类调用主类的公共(public)方法

c# - 如何在 RDLC 报告中添加汇总字段?

Python tkinter网格布局问题