如何在一个线程中使用.net async CTP

时间:2012-08-02 13:23:42

标签: c# asynchronous tap ctp

所以我最近一直在阅读关于网络异步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这样的事情来卸载我们的工作,并且不会开始它在另一个线程?如果是这样的话,为什么所有这一臂都放弃了多线程不会混淆异步?

3 个答案:

答案 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.StartTask.RunTask.Factory.StartNew