winforms:使用 parallel.foreach 更新进度 [英] winforms: updating progress with a parallel.foreach

查看:27
本文介绍了winforms:使用 parallel.foreach 更新进度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I haven't seen any posts pertaining to my issue, so I apologize if I post a question already asked.

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

I have a windows form program, c#, that checks stocks and does analysis. The main form launches another form, via a new thread and ShowDialog. While it's loading, it's running a parallel.foreach. In that parallel.foreach, I'd like to show progress on the main form.

我遇到了跨线程问题,并添加了 invoke,尽管它似乎不是线程安全的,因为它似乎在 parallel.foreach 结束时陷入僵局.我试过委托,事件,没有运气.帮助我欧比旺斯,你是我唯一的希望!

I've run into cross-threading issues, and added invoke, although it doesn't appear to be thread-safe as it seems to be deadlocking toward the end of the parallel.foreach. I've tried delegates, events, no luck. Help me Obi-Wans, you're my only hope!

精简版:

主要形式

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 中定义的这些方法签名中无法解决这个问题)

Update 1: If I move the progress update label to the child form, it appears I am getting all the progress updates. I had to move from the Load event to the Shown event so that the form renders, so users can see the progress updates. I had to follow SLaks advice though and run Task.Run(() => Parallel.ForEach. This will work for me. Would still like to figure out why it still locks up toward the end if I wanted the progress updates on the main form. (I've always read async void was bad, but I guess no way around this in these defined method signatures in 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 是一个阻塞调用;它也在调用线程上运行委托.因此,UI 在完成之前无法更新.

Parallel.ForEach is a blocking call; it runs delegates on the calling thread too. Therefore, the UI cannot update until it finishes.

相反,你应该使用 awaitTask.WhenAll(如果你在做异步工作)或 Task.Run(() => Parallel.ForEach(...))(如果它受 CPU 限制),以便您让 UI 线程空闲并能够更新.

Instead, you should use await with Task.WhenAll (if you're doing async work) or Task.Run(() => Parallel.ForEach(...)) (if it's CPU-bound) so that you leave the UI thread idle and able to update.

这篇关于winforms:使用 parallel.foreach 更新进度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆