EN *_*eer 4 c# parallel-processing multithreading .net-4.0
我开始尝试向Windows窗体添加进度条,以更新在Parallel.Foreach循环中运行的代码的进度.为此,UI线程必须可用于更新进度条.我使用Task来运行Parallel.Foreach循环以允许UI线程更新进度条.
在Parallel.Foreach循环中完成的工作相当密集.在使用Task运行程序的可执行文件(不在visual studio中调试)之后,程序没有响应.如果我在没有Task的情况下运行程序,情况就不是这样.我在两个实例之间注意到的关键区别是,在没有Task的情况下运行时程序需要大约80%的cpu,在使用Task运行时大约需要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);
}
}
Run Code Online (Sandbox Code Playgroud)
旁注:我知道
Interlocked.Increment(ref int___);
Run Code Online (Sandbox Code Playgroud)
用来代替锁.它被认为更有效吗?
我的问题有三个方面:
1.)当负载少得多时,为什么带有Task的程序会无响应?
2.)使用Task运行Parallel.Foreach是否将Parallel.Foreach的线程池限制为只运行任务的线程?
3.)有没有办法让UI线程响应而不是在没有使用取消令牌的情况下休眠.1秒的持续时间?
我很感激任何帮助或想法,我花了很多时间研究这个.如果我违反任何发布格式或规则,我也会道歉.我试图坚持他们,但可能错过了一些东西.
通过使用Invoke
在拥有的Windows同步上下文中调用委托的内置方法,可以极大地简化代码.
来自MSDN:
在拥有控件的基础窗口句柄的线程上执行指定的委托.
Invoke方法搜索控件的父链,直到找到具有窗口句柄的控件或窗体(如果当前控件的基础窗口句柄尚不存在).
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++));
}));
}
}
Run Code Online (Sandbox Code Playgroud)
这将从Action
Task中调用表单所属的同一UI线程上的委托.
现在试着回答你的问题
1.)当负载少得多时,为什么带有Task的程序会无响应?
我不是100%肯定,但这可能与您在UI线程上锁定成员有关.如果负载较小,则锁定将更频繁地发生,可能导致UI线程在进度条增加时"挂起".
您还运行一个每100毫秒睡眠UI线程的while循环.你会看到UI因为while循环而挂起.
2.)使用Task运行Parallel.Foreach是否将Parallel.Foreach的线程池限制为只运行任务的线程?
它不是.将在Parallel.ForEach
调用中创建几个任务.底层ForEach
使用分区器来分散工作,而不是创建比必要的更多的任务.它分批创建任务,并处理批次.
3.)有没有办法让UI线程响应而不是在没有使用取消令牌的情况下休眠.1秒的持续时间?
我能够通过删除while
循环并使用该Invoke
方法直接在UI线程上执行lambda 来处理它.
归档时间: |
|
查看次数: |
2133 次 |
最近记录: |