![](/img/trans.png)
[英]How I can see the Async state machine (async/await under the hood) with the help of DotPeek?
[英]async and await without “threads”? Can I customize what happens under-the-hood?
我有一个问题,关于如何自定义新的async
/ await
关键字和C#4.5中的Task
类。
首先是了解我的问题的一些背景:我正在开发一个具有以下设计的框架:
Update()
函数,它枚举列表并查看是否需要执行某些“事情”并执行此操作。 基本上它就像一个大线程的sheduler。 为简单起见,让我们假设了“要做的事情”是返回布尔函数true
当他们“完成”(且不应被称为下一个更新)和false
当sheduler应该再打电话给他们下一次更新。 Update()
函数中迭代几个hundret事情。 一个例子:
Future f1, f2;
bool SomeThingToDo() // returns true when "finished"
{
if (f1 == null)
f1 = Remote1.CallF1();
else if (f1.IsComplete && f2 == null)
f2 = Remote2.CallF2();
else if (f2 != null && f2.IsComplete)
return true;
return false;
}
现在这一切听起来像async
和await
C#5.0一样可以帮助我。 我没有100%完全理解它在幕后做了什么(任何好的参考?),但是当我从一些我已经看过的谈话中得到它时,它完全符合我想要的这个非常简单的代码:
async Task SomeThingToDo() // returning task is completed when this is finished.
{
await Remote1.CallF1();
await Remote2.CallF2();
}
但我无法找到一种方法来编写我的Update()
函数来实现这样的事情。 async
和await
似乎想要使用Task
- 这反过来似乎需要真正的线程?
迄今为止我最接近的“解决方案”:
第一个线程(运行SomeThingToDo
)只调用它们的函数一次并存储返回的任务并测试每个Update()
是否完成任务。
Remote1.CallF1
返回一个新的Task,其中一个空的Action作为构造函数参数,并记住返回的任务。 当F1实际完成时,它会在任务上调用RunSynchronously()
将其标记为已完成。
在我看来,这似乎是对任务系统的歪曲。 除此之外,它会在两个线程之间创建共享内存(Task的IsComplete
布尔值),如果可能的话,我希望用我们的远程Messanging系统替换它们。
最后,它没有解决我的问题,因为它不适SomeThingToDo
上面的类似await的SomeThingToDo
实现。 似乎异步函数返回的自动生成的Task对象立即完成?
最后我的问题:
Task<T>
吗? Task
没有任何涉及到“堵”和“线”? async
和await
时究竟发生了什么? 我没有100%完全理解它在引擎盖下做了什么 - 任何好的参考?
回到我们设计Mads时,Stephen和我在MSDN杂志的各个不同层面上写了一些文章。 链接在这里:
http://blogs.msdn.com/b/ericlippert/archive/2011/10/03/async-articles.aspx
从我的文章开始,然后是Mads's,然后是Stephen's。
似乎异步函数返回的自动生成的Task对象立即完成?
不,它们在方法体中的代码返回或抛出时完成,与任何其他代码相同。
我可以挂钩到async / await来使用我自己的实现而不是
Task<T>
吗?
包含 await
方法必须返回void
, Task
或Task<T>
。 但是,只要您可以在其上调用GetAwaiter()
, 等待的表达式就可以返回任何类型。 这不一定是Task
。
如果那是不可能的,我可以使用任何没有任何与“阻塞”和“线程”相关的任务吗?
绝对。 Task
只是代表将来完成的工作。 虽然这项工作通常在另一个线程上完成,但没有要求 。
我可以挂钩到async / await来使用我自己的实现而不是Task吗?
是。
如果那是不可能的,我可以使用任何没有任何与“阻塞”和“线程”相关的任务吗?
是。
什么好的参考我写异步和等待时究竟发生了什么?
是。
我不鼓励你问是/否问题。 你可能不只是想要是/否答案。
async和await似乎想要使用Task - 这反过来似乎需要真正的线程?
不,那不是真的。 Task
表示可以在将来的某个时间点完成的事情,可能会产生结果。 它有时在另一个线程一些计算的结果,但它并不需要的人。 它可以是未来某个时刻发生的任何事情。 例如,它可能是IO操作的结果。
Remote1.CallF1
返回一个新的Task,其中一个空的Action作为构造函数参数,并记住返回的任务。 当F1实际完成时,它会在任务上调用RunSynchronously()
将其标记为已完成。
所以你在这里缺少的是TaskCompletionSource
类。 有了这个缺失的拼图,很多东西都应该适合。 您可以创建TCS对象,将Task
从它的Task
属性传递给... whoomever,然后使用SetResult
属性来指示它的完成。 这样做不会导致创建任何其他线程,也不会使用线程池。
请注意,如果您没有结果并且只想要一个Task
而不是Task<T>
那么只需使用TaskCompletionSource<bool>
或其他类似的东西,然后使用SetResult(false)
或其他任何合适的东西。 通过将Task<bool>
转换为Task
您可以从公共API隐藏该实现。
这也应该提供您提出的前两个问题的“如何”变体,而不是您提出的“我可以”版本。 你可以使用TaskCompletionSource
来生成一个任务,只要你说它就完成了,使用你想要的任何异步构造,这可能涉及或不涉及使用额外的线程。
回答你的问题:
我可以挂钩到async / await来使用我自己的实现而不是Task吗?
是。 你可以等待任何事情 。 但是,我不推荐这个。
如果那是不可能的,我可以使用任何没有任何与“阻塞”和“线程”相关的任务吗?
Task
类型代表未来 。 它不一定在线程上“运行”; 它可以表示下载完成或计时器到期等。
什么好的参考我写异步和等待时究竟发生了什么?
如果你的意思是代码转换, 这篇博文有一个很好的并排。 它的细节并不是100%准确,但它足以写一个简单的定制等待者。
如果你真的想扭曲async
来进行竞标,Jon Skeet的eduasync系列是最好的资源。 但是,我真的不建议你在制作中这样做。
您可能会发现我的async
/ await
介绍对async
概念的介绍以及使用它们的推荐方法很有帮助。 官方MSDN文档也非常好。
我确实编写了可能适用于您的情况的AsyncContext
和AsyncContextThread
类 ; 它们为async
/ await
方法定义了单线程上下文。 您可以使用Factory
属性将工作(或发送消息)排队到AsyncContextThread
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.