所以我最近一直在阅读关于网络异步CTP的一些内容,而且不断出现的一件事就是这样的句子:“异步不是关于启动新线程,关于多路复用工作”和“不同步”多线程是一个相同的想法[作为协作式多任务处理]。你做了一段时间的任务,当它产生控制时,你在那个线程上做了一段时间的另一个任务“。
我试图理解这样的评论是纯粹的(好的,大多数)是深奥的还是学术性的,或者是否有一些语言构造我忽略了允许我通过“等待”开始的任务在UI上神奇地运行线程。
在他的博客中,Eric Lippert将此示例作为演示如何在没有多线程的情况下使用Asyncrhony的示例:
async void FrobAll()
{
for(int i = 0; i < 100; ++i)
{
await FrobAsync(i); // somehow get a started task for doing a Frob(i) operation on this thread
}
}
现在,这是引起我兴趣的评论:“...在这个帖子上做一个Frob(i)操作的启动任务”。
这怎么可能?这主要是理论上的评论吗?到目前为止我可以看到的唯一一个任务似乎不需要一个单独的线程(好吧,除非你检查代码,否则你无法确定),就像Task.Delay(),可以等待没有开始另一个线程。但我认为这是一个特例,因为我没有为此编写代码。
对于想要从GUI线程卸载他们自己的一些长时间运行代码的普通用户,我们不是主要讨论做像Task.Run这样的事情来卸载我们的工作,并且不会开始它在另一个线程?如果是这样的话,为什么所有这一臂都放弃了多线程不会混淆异步?
答案 0 :(得分:2)
请参阅我的intro to async
/await
。
在CPU工作的情况下,您必须使用Task.Run
之类的东西在另一个线程中执行它。但是,有很多工作不是CPU工作(网络请求,文件系统请求,定时器......),而且每个工作都可以包含在Task
中而不用使用线程。
请记住,在驱动程序级别,所有都是异步的。同步Win32 API只是便利包装器。
答案 1 :(得分:2)
不是100%肯定,但从文章中可以看出,它允许在FrobAsync
的调用之间交错显示Windows消息(调整大小事件,鼠标点击等)。大致类似于:
void FrobAll()
{
for(int i = 0; i < 100; ++i)
{
FrobAsync(i); // somehow get a started task for doing a Frob(i) operation on this thread
System.Windows.Forms.Application.DoEvents();
}
}
或者更准确地说:
void FrobAll()
{
SynchronizationContext.Current.Post(QueueFrob, 0);
}
void QueueFrob(Object state) {
var i = (int)state;
FrobAsync(i);
if (i == 99) return;
SynchronizationContext.Current.Post(QueueFrob, i+1);
}
在每次迭代之间没有对DoEvents
的讨厌调用。之所以发生这种情况,是因为对await的调用会发送一条将FrobAsync
调用入队的Windows消息,允许在下一次Frobbing开始之前执行Frobbings之间发生的任何Windows消息。
答案 2 :(得分:1)
async
/ await
只是异步。从调用者方面来看,无论是否使用多个线程都无关紧要 - 只是它做了异步的事情。例如,IO完成端口是异步的,但不执行任何多线程(在后台线程上完成操作;但是在该线程上没有完成“工作”)。
从await
关键字,“多线程”毫无意义。异步操作的作用是实现细节。
从Eric的例子来看,该方法可以实现如下:
return Task.Factory.StartNew(SomeMethod,
TaskScheduler.FromCurrentSynchronizationContext());
这实际上意味着当当前线程完成所有当前排队的工作时,对SomeMethod
的调用进行排队。这与FrobAsync
的调用者异步,FrobAsync
可能会在执行SomeMethod
之前返回。
现在,FrobAsync
可以实现使用多线程,在这种情况下它可以像这样编写:
return Task.Factory.StartNew(SomeMethod);
如果未更改默认的TaskScheduler,则使用线程池。但是,从调用者的角度来看,没有任何改变 - 你仍然await
方法。
从多线程的角度来看,这就是你应该关注的内容。使用Task.Start
,Task.Run
或Task.Factory.StartNew
。