简体   繁体   English

线程阻止UI

[英]Thread Blocking the UI

I was following an example from C# in a Nutshell. 我在Nutshell中关注了C#中的一个例子。 According to the text the following code is supposed to be non blocking, but I find that the form will not display until the 5 seconds have passed. 根据文本,下面的代码应该是非阻塞的,但我发现表单将在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());
}

I have a feeling it's something to do with Thread.Sleep() and instead of putting the new Thread to sleep, it's putting the main Thread to sleep. 我感觉这与Thread.Sleep()有关,而不是让新线程处于休眠状态,而是让主线程处于休眠状态。

Why is it blocking the UI thread? 为什么它会阻止UI线程?

When you are trying to get result of task task.Result main thread will be blocked until task will finish it's execution (ie result will be available). 当你试图获得任务task.Result主线程的结果将被阻止,直到任务完成它的执行(即结果将可用)。 Use task.ContinueWith if you don't want to wait for async operation completion: 如果您不想等待异步操作完成,请使用task.ContinueWith

Task<int> task = tcs.Task;
task.ContinueWith(t => {         
     MessageBox.Show(t.Result.ToString());
});

BTW there is nice feature in .NET 4.5 for resuming suspended operation when task is completed - async methods: 顺便说一句,.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());
}

This method will yield control to caller immediately after starting to wait for task result. 在开始等待任务结果后,此方法将立即对调用者进行控制。 When result will be available, method will continue execution and show message. 当结果可用时,方法将继续执行并显示消息。

Actually as @Servy pointed in comments, async method which return void is not very good practice (eg for error handling), but sometimes it's OK to use them for event handlers. 实际上,正如@Servy在注释中指出的那样,返回void异步方法并不是很好的实践(例如,用于错误处理),但有时可以将它们用于事件处理程序。

When you call Task.Result.ToString() (in the MessageBox.Show ) the Task class has a mechanism that waits for the task to be finished before actually giving you the result (as it doesn't actually have it until the Task finishes. Here's my proof: 当你调用Task.Result.ToString() (在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());
}

You will see that it shows you the 2.5sec message box before the messagebox with 42. (in fact, 2.5 seconds before that). 您将看到它在消息框之前显示了2.5秒消息框(实际上,在此之前的2.5秒)。

What you are looking for is this: 你在寻找的是:

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()));
}

This will not freeze the UI thread. 不会冻结UI线程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM