在form里面,新开线程运行
Thread objThread = new Thread(new ThreadStart(delegate
{
Start();
}));
objThread.Start();
Start函数里面调用了一个类,这个类里面有一个循环运行的方法。在这个方法里面使用task调用一个FUNC
Func<object, string> taskfunc = test;// MakeTaskRequest;// test;
Task<string> tt = Task.Factory.StartNew<string>(taskfunc, param);
private string test(object obj)
{
Thread.Sleep(50);
Interlocked.Increment(ref responsecount);
Interlocked.Decrement(ref threadscount);
return "ok\r\n";
}
使用这个代码,发现UI假死。
但是,如果我不用task,直接在循环方法里面用
Thread.Sleep(500);
Interlocked.Increment(ref responsecount);
Interlocked.Decrement(ref threadscount);
来代替task.Factory.StartNew,UI就不会失去响应
谁知道问题出在哪?
------解决思路----------------------
帮你看了一下,问题找到了,其实你的界面卡死的原因也不是上面说的一些原因,虽然在32位跟64位操作系统有不同的线程数限制,但你的原因不在这里。
你的逻辑是这样的:
主线程》子线程》30000工作线程
在循环体内,你的3000工作线程有更新主界面lblStatus的操作,但紧接下来子线程又要进行了更新操作,工作线程与子线程相互之间在"抢夺委托",但你没有对他们的操作进行“顺序”限制,你如果将更细操作全部放入工作线程内去更新控件,或全部由子线程去更新就没这个问题。
for (int i = 0; i < 30000; i++)
{
//工作线程方法内要更新lblStatus控件
Task<string> tt = Task.Factory.StartNew<string>(test, i);
tt.ContinueWith((t) =>
{
if (t.IsFaulted)
{
string msg=(string.Format("I have observed a {0}", t.Exception.InnerException.GetType().Name));
Interlocked.Increment(ref responsecount);
Interlocked.Decrement(ref threadscount);
}
else
{
//WriteMessage(t.Result);
}
});
Interlocked.Increment(ref threadscount);
Interlocked.Increment(ref requestcount);
//紧接着子线程要更新lblStatus控件
WriteStatus("已使用线程数:" + threadscount.ToString() +
" 已发送请求数:" + requestcount.ToString() +
" 已完成请求数:" + responsecount.ToString());
if (_isStop)
{
WriteMessage("正在退出...");
break;
}
}
改一下
for (int i = 0; i < 30000; i++)
{
//工作线程方法内要更新lblStatus控件
Task<string> tt = Task.Factory.StartNew<string>(test, i);
tt.ContinueWith((t) =>
{
if (t.IsFaulted)
{
string msg=(string.Format("I have observed a {0}", t.Exception.InnerException.GetType().Name));
Interlocked.Increment(ref responsecount);
Interlocked.Decrement(ref threadscount);
}
else
{
//WriteMessage(t.Result);
}
//全部交给工作线程去完成界面更新
Interlocked.Increment(ref threadscount);
Interlocked.Increment(ref requestcount);
WriteStatus("已使用线程数:" + threadscount.ToString() +
" 已发送请求数:" + requestcount.ToString() +
" 已完成请求数:" + responsecount.ToString());
if (_isStop)
{
WriteMessage("正在退出...");
return;
}
});
}
这样就没问题了
------解决思路----------------------
你说提出来是指不用 Task 调用 test,而是直接调用 test 么? 那是因为 test 里面使用了Thread.Sleep,大大降低了循环的速度。如果把 test 里面的Thread.Sleep注释掉,就还是会假死的。而用 Task 的话,test 里面的Thread.Sleep是阻塞了线程池线程,循环的速度没有降低。
另外,#13 那样的方式,把 UI 更新请求写到了 Task 的延续里,也是在线程池线程上运行,当然也不会假死。因为那样也会大幅降低 UI 更新请求的速度。或者说,只要你用某种方式,让发起 UI 更新请求的速度低于 UI 处理请求的速度,就不会假死。