c# - winforms:使用 parallel.foreach 更新进度

标签 c# multithreading winforms parallel.foreach

我还没有看到任何与我的问题相关的帖子,所以如果我发布一个已经被问到的问题,我深表歉意。

我有一个 Windows 窗体程序,C#,可以检查股票并进行分析。主窗体通过新线程和 ShowDialog 启动另一个窗体。在加载时,它正在运行 parallel.foreach。在那个 parallel.foreach 中,我想在主窗体上显示进度。

我遇到了跨线程问题,并添加了调用,尽管它似乎不是线程安全的,因为它似乎在 parallel.foreach 的末尾发生死锁。我试过代表、事件,但没有成功。帮助我,欧比旺,你是我唯一的希望!

精简版:

主窗体

private void button1_Click(object sender, EventArgs e)
    {
        YearLows yearLows = new YearLows();
        Thread yearLowsThread = new Thread(() => StartYearLows(yearLows));
        yearLowsThread.Start();
        btnGetYearLows.Enabled = false;
    }

    private void StartYearLows(YearLows yearLows)
    {
        yearLows.ShowDialog();
    }

    public void UpdateProgress(string text)
    {
        lblProgress.Text = text;
    }

第二个表单对话框

    public partial class YearLows : Form
    {
        private void YearLows_Load(object sender, EventArgs e)
        {
            // work
            Parallel.ForEach(responseStocks, new ParallelOptions { MaxDegreeOfParallelism = MaxThreads }, x =>
            {
              // more work
              Interlocked.Increment(stocksProcessed);
              UpdateProgress($"{stocksProcessed} / {stocksTotal} Researched");
            });
        }

        private void UpdateProgress(string text)
        {
            Invoke(new Action(() => frmMain.UpdateProgress(text)));
        }
    }

更新 1: 如果我将进度更新标签移动到子窗体,看起来我正在获取所有进度更新。我必须从 Load 事件移动到 Shown 事件,以便呈现表单,以便用户可以看到进度更新。不过,我必须遵循 SLaks 的建议并运行 Task.Run(() => Parallel.ForEach。这对我有用。如果我想在主屏幕上进行进度更新,我仍然想弄清楚为什么它仍然会在最后锁定形式。(我一直读到 async void 很糟糕,但我想在 winforms 中这些定义的方法签名中没有办法解决这个问题)

    public partial class YearLows : Form
    {
        private async void YearLows_Shown(object sender, EventArgs e)
        {
            await AnalyzeStocks();
        }

        private async Task AnalyzeStocks(object sender, EventArgs e)
        {
            // work
            await Task.Run(() => Parallel.ForEach(responseStocks, new ParallelOptions { MaxDegreeOfParallelism = MaxThreads }, x =>
            {
                // more work
                Interlocked.Increment(stocksProcessed);
                UpdateProgress($"{stocksProcessed} / {stocksTotal} Researched");
            }));
        }

        private void UpdateProgress(string text)
        {
            Invoke(new Action(() => lblProgress.UpdateProgress(text)));
        }
    }

最佳答案

Parallel.ForEach 是一个阻塞调用;它也在调用线程上运行委托(delegate)。因此,UI 在完成之前无法更新。

相反,您应该将 awaitTask.WhenAll(如果您正在进行异步工作)或 Task.Run(() => Parallel。 ForEach(...))(如果它受 CPU 限制)这样您就可以让 UI 线程空闲并能够更新。

关于c# - winforms:使用 parallel.foreach 更新进度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51092054/

相关文章:

C++0x "Hello Concurrent World"在 g++/linux 上立即出现段错误?

c# - .Net 客户端超时

c# - 评论我的简单 MVP Winforms 应用程序

c# - 如何使用方法添加多个变化的值

c# - 三元运算符叠加

c# - 管理具有不同输出的任务

c# - AutoMapper map Int

c# - 执行 native 代码时收到 SIGSEGV。这通常表示单声道运行时出现 fatal error

java - FutureTask.get 方法永远阻塞,尽管我正在从另一个线程设置它的值

c# - 设置锁时线程关闭时锁会发生什么