Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/268.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在.NET4.0中将Task与Parallel.Foreach一起使用_C#_Multithreading_.net 4.0_Parallel Processing - Fatal编程技术网

C# 在.NET4.0中将Task与Parallel.Foreach一起使用

C# 在.NET4.0中将Task与Parallel.Foreach一起使用,c#,multithreading,.net-4.0,parallel-processing,C#,Multithreading,.net 4.0,Parallel Processing,我开始尝试在windows窗体中添加一个进度条,用于更新在Parallel.Foreach循环中运行的代码的进度。为了做到这一点,UI线程必须可用于更新进度条。我使用了一个任务来运行Parallel.Foreach循环,以允许UI线程更新进度条 在Parallel.Foreach循环中所做的工作相当密集。在使用任务运行程序的可执行文件(而不是在visual studio中调试)后,程序变得无响应。如果我在没有任务的情况下运行程序,情况就不是这样了。我注意到这两个实例之间的关键区别是,当不运行任务

我开始尝试在windows窗体中添加一个进度条,用于更新在Parallel.Foreach循环中运行的代码的进度。为了做到这一点,UI线程必须可用于更新进度条。我使用了一个任务来运行Parallel.Foreach循环,以允许UI线程更新进度条

在Parallel.Foreach循环中所做的工作相当密集。在使用任务运行程序的可执行文件(而不是在visual studio中调试)后,程序变得无响应。如果我在没有任务的情况下运行程序,情况就不是这样了。我注意到这两个实例之间的关键区别是,当不运行任务时,程序占用约80%的cpu,当运行任务时,占用约5%

private void btnGenerate_Click(object sender, EventArgs e)
    {
        var list = GenerateList();
        int value = 0;
        var progressLock = new object ();

        progressBar1.Maximum = list.Count();

        Task t = new Task(() => Parallel.ForEach (list, item =>
        {
                DoWork ();
                lock (progressLock)
                {
                    value += 1;
                }
        }));

        t.Start();

        while (!t.IsCompleted)
        {
            progressBar1.Value = value;
            Thread.Sleep (100);
        }
    }
旁注:我知道

 Interlocked.Increment(ref int___);
代替锁工作。它被认为更有效吗

我的问题有三个方面:

1.)当负载大大减少时,为什么带有任务的程序会变得无响应

2.)使用Task运行Parallel.Foreach是否将Parallel.Foreach的线程池限制为仅运行任务的线程

3.)有没有一种方法可以使UI线程响应,而不是在不使用取消令牌的情况下休眠.1秒


我很感激任何帮助或想法,我已经花了很多时间研究这个。我也很抱歉,如果我违反了任何张贴格式或规则。我试图遵守它们,但可能遗漏了一些东西。

通过使用内置的
Invoke
方法,您可以大大简化那里的代码,该方法调用所属Windows同步上下文上的委托

发件人:

在拥有控件底层窗口句柄的线程上执行指定的委托

Invoke方法向上搜索控件的父链,直到找到具有窗口句柄的控件或窗体(如果当前控件的底层窗口句柄尚不存在)

这将从任务中调用表单所属的同一UI线程上的
操作
委托

现在试着回答你的问题

1.)当负载大大减少时,为什么带有任务的程序会变得无响应

我不是100%确定,但这可能与您在UI线程上锁定成员有关。如果负载更少,那么锁定将更频繁地发生,这可能导致在progressbar增加时UI线程“挂起”

您还运行了一个while循环,该循环每100毫秒睡眠一次UI线程。您将看到UI由于while循环而挂起

2.)使用Task运行Parallel.Foreach是否将Parallel.Foreach的线程池限制为仅运行任务的线程

事实并非如此。将在
Parallel.ForEach调用中创建多个任务。基本的
ForEach
使用a来分散工作,并且不会创建超出必要范围的任务。它批量创建任务,并处理这些批

3.)有没有一种方法可以使UI线程响应,而不是在不使用取消令牌的情况下休眠.1秒


我可以通过移除
while
循环,并使用
Invoke
方法直接在UI线程上执行lambda来处理这个问题。

在UI线程上的循环中等待任务完成就像在UI线程上执行它一样(甚至更糟)。查看
BackgroundWorker
async
如果
DoWork()
访问任何UI元素,将导致死锁发生。JohnathonSullinger-DoWork()不访问任何UI元素@Yorye Nathan-你能详细说明或举个例子吗?在今天之前,我从未做过任何关于多线程的事情。也许是与此相关的事情?对于.Net 4.5来说,这是一个很好的解决方案,但问题被标记为.Net-4.0。OP可以用一个更新进度条吗?啊,我错过了。是的,他们可以。我会用一个例子更新我的答案。谢谢你的回复!不幸的是,我正在从事的项目使用的是.NET4.0,据我所知,它不支持Progress(t)类。编辑:没有看到有人已经发现了这一点。@ENSpeer Microsoft在4.0中提供了
Progres
,您只需安装NuGet软件包也很抱歉这样做,但我必须执行-1以获得建议“在UI线程的while循环中使用
DoEvents()
”,这几乎从来都不好做
DoEvents()
在循环中,如果您发现需要在循环中使用
DoEvents()
,正确的建议是“您应该重写代码,以便不需要在UI线程上执行while循环”。您在回答中使用了正确的方式(使用
Invoke
),但您不应该推荐
DoEvents()
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    string[] GenerateList() => new string[500];
    void DoWork()
    {
        Thread.Sleep(50);
    }

    private void button1_Click(object sender, EventArgs e)
    {
        var list = GenerateList();
        progressBar1.Maximum = list.Length;

        Task.Run(() => Parallel.ForEach(list, item =>
        {
            DoWork();

            // Update the progress bar on the Synchronization Context that owns this Form.
            this.Invoke(new Action(() => this.progressBar1.Value++));
        }));
    }
}