这是一个使用异步且从不使用多个线程的程序示例:
public class Foo
{
private int _value;
private TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
public int Value
{
get
{
return _value;
}
set
{
_value = value;
var oldTCS = tcs;
tcs = new TaskCompletionSource<bool>();
oldTCS.SetResult(true);
}
}
public Task ValueChanged()
{
return tcs.Task;
}
}
private static void Main(string[] args)
{
Foo foo = new Foo();
foo.ValueChanged()
.ContinueWith(t =>
{
Console.WriteLine(foo.Value);
}, TaskContinuationOptions.ExecuteSynchronously);
foo.Value = 5;
}
Task
返回的 from将ValueChanged
在下次Value
更改时完成。该类的用户Foo
可以获取该返回的任务,并根据尚未发生的操作连接延续以在该任务上运行。然后,在未来的某个时间点, 的值发生了foo
变化,延续将运行。请注意, foo 对象可以传递给其他一些完全未知的函数,Main
最终设置该值(以说明为什么您可能想要做这样的事情)。
不需要新线程来创建Task
,也不需要执行延续。
这是另一个更实用的示例:
我们将从这个简单的(扩展)方法开始,它接受一个表单并返回一个Task
指示该表单下一次关闭的时间:
public static class FormExtensions
{
public static Task WhenClosed(this Form form)
{
var tcs = new TaskCompletionSource<bool>();
form.FormClosed += (sender, args) => tcs.SetResult(true);
return tcs.Task;
}
}
现在我们可以用我们的一种形式来实现它:
private async void button1_Click(object sender, EventArgs args)
{
Form2 otherForm = new Form2();
otherForm.Show();
await otherForm.WhenClosed();
//take some data from that form and display it on this form:
textBox1.Text = otherForm.Name;
}
创建和显示另一种形式从不涉及创建新线程。此表单和新表单都完全使用一个 UI 线程来创建和修改。
Task
返回 from的创建WhenClosed
根本不需要创建新线程。
Task
等待时,不会创建新线程。当前方法结束,UI 线程返回处理消息。在某些时候,同一个 UI 线程会做一些导致第二个表单关闭的事情。这将导致任务继续运行,从而将我们返回到我们设置文本框文本的按钮单击处理程序。
所有这些都完全由 UI 线程完成,没有创建其他线程。然而我们只是“等待”(实际上没有等待)一个长时间运行的操作完成(用户将一些信息放入第二个表单然后关闭它)而不阻塞 UI 线程,从而保持主表单响应。