Jam*_*ery 6 c# task-parallel-library
我在Nutshell中关注了C#中的一个例子.根据文本,下面的代码应该是非阻塞的,但我发现表单将在5秒过后才会显示.
private void Form1_Load(object sender, EventArgs e)
{
var tcs = new TaskCompletionSource<int>();
new Thread(() => {Thread.Sleep(5000); tcs.SetResult(42); }).Start();
Task<int> task = tcs.Task;
MessageBox.Show(task.Result.ToString());
}
Run Code Online (Sandbox Code Playgroud)
我觉得这与Thread.Sleep()有关,而不是让新线程处于休眠状态,而是让主线程处于休眠状态.
为什么它会阻止UI线程?
Ser*_*kiy 11
当你试图获得任务task.Result主线程的结果将被阻止,直到任务完成它的执行(即结果将可用).使用task.ContinueWith,如果你不想等待异步操作完成:
Task<int> task = tcs.Task;
task.ContinueWith(t => {
MessageBox.Show(t.Result.ToString());
});
Run Code Online (Sandbox Code Playgroud)
顺便说一句,.NET 4.5中有很好的功能可以在任务完成时恢复挂起操作 - 异步方法:
private async void Form1_Load(object sender, EventArgs e)
{
var tcs = new TaskCompletionSource<int>();
new Thread(() => { Thread.Sleep(2000); tcs.SetResult(42); }).Start();
int result = await tcs.Task;
MessageBox.Show(result.ToString());
}
Run Code Online (Sandbox Code Playgroud)
在开始等待任务结果后,此方法将立即对调用者进行控制.当结果可用时,方法将继续执行并显示消息.
实际上正如@Servy在注释中指出的那样,返回的异步方法void不是很好的实践(例如用于错误处理),但有时可以将它们用于事件处理程序.
当你调用Task.Result.ToString()(in MessageBox.Show)时,Task类有一个机制,在实际给你结果之前等待任务完成(因为它实际上没有它直到Task完成.这是我的证明:
private void Form1_Load(object sender, EventArgs e)
{
var tcs = new TaskCompletionSource<int>();
new Thread(() => {Thread.Sleep(5000); tcs.SetResult(42); }).Start();
Task<int> task = tcs.Task;
Thread.Sleep(2500);
MessageBox.Show("Waited for 2.5secs on UI thread.");
MessageBox.Show(task.Result.ToString());
}
Run Code Online (Sandbox Code Playgroud)
您将看到它在消息框之前显示2.5秒消息框,其中包含42.(事实上,在此之前的2.5秒).
你在寻找的是:
private void Form1_Load(object sender, EventArgs e)
{
var tcs = new TaskCompletionSource<int>();
new Thread(() => {Thread.Sleep(5000); tcs.SetResult(42); }).Start();
Task<int> task = tcs.Task;
task.ContinueWith(t => MessageBox.Show(t.Result.ToString()));
}
Run Code Online (Sandbox Code Playgroud)
这不会冻结UI线程.
| 归档时间: |
|
| 查看次数: |
1353 次 |
| 最近记录: |