如何在没有Async CTP的情况下实现等待
您将如何实现与Async CTP await
关键字类似的function? 是否存在一个简单的实现,在所有情况下都像await
一样,或者是否需要针对不同场景的不同实现?
await
总是涉及同样的转变 – 但这是一个非常痛苦的转变。 await
的库侧不是太复杂,但棘手的是编译器为您构建状态机,允许继续跳回到正确的位置。
我可能会使用迭代器块(产量返回),你可以伪造类似的东西……但它会非常丑陋。
几周前我给出了一个关于编译器在幕后做什么的DevExpress网络研讨会 – 它显示了几个例子中的反编译代码,以及解释编译器如何构建要返回的任务,以及“awaiter”具有什么做。 它可能对您有用。
新的await
关键字与现有的yield return
关键字具有相似的语义,因为它们都会使编译器为您生成延续样式状态机。 因此,可以使用与Async CTP具有一些相同行为的迭代器来一起破解某些东西。
这是它的样子。
public class Form1 : Form { private void Button1_Click(object sender, EventArgs e) { AsyncHelper.Invoke(PerformOperation); } private IEnumerable PerformOperation(TaskCompletionSource tcs) { Button1.Enabled = false; for (int i = 0; i < 10; i++) { textBox1.Text = "Before await " + Thread.CurrentThread.ManagedThreadId.ToString(); yield return SomeOperationAsync(); // Await textBox1.Text = "After await " + Thread.CurrentThread.ManagedThreadId.ToString(); } Button2.Enabled = true; tcs.SetResult(true); // Return true } private Task SomeOperationAsync() { // Simulate an asynchronous operation. return Task.Factory.StartNew(() => Thread.Sleep(1000)); } }
由于yield return
生成一个IEnumerable
我们的协同程序必须返回一个IEnumerable
。 所有的魔法都发生在AsyncHelper.Invoke
方法中。 这就是让我们的协程(伪装成黑客迭代器)的原因。 需要特别注意确保迭代器始终在当前同步上下文中执行,如果存在迭代器,则在尝试模拟await
在UI线程上的工作方式时非常重要。 它通过同步执行第一个MoveNext
,然后使用SynchronizationContext.Send
从工作线程执行其余工作来完成此操作,工作线程也用于异步等待各个步骤。
public static class AsyncHelper { public static Task Invoke (Func, IEnumerable> method) { var context = SynchronizationContext.Current; var tcs = new TaskCompletionSource(); var steps = method(tcs); var enumerator = steps.GetEnumerator(); bool more = enumerator.MoveNext(); Task.Factory.StartNew( () => { while (more) { enumerator.Current.Wait(); if (context != null) { context.Send( state => { more = enumerator.MoveNext(); } , null); } else { enumerator.MoveNext(); } } }).ContinueWith( (task) => { if (!tcs.Task.IsCompleted) { tcs.SetResult(default(T)); } }); return tcs.Task; } }
关于TaskCompletionSource
的全部内容是我尝试复制await
可以“返回”一个值的方式。 问题是协程必须实际返回一个IEnumerable
因为它只不过是一个被黑客攻击的迭代器。 所以我需要提出一种替代机制来捕获返回值。
这有一些明显的局限性,但我希望这能给你一般的想法。 它还演示了CLR如何具有一种用于实现协程的通用机制, await
和yield return
将无处不在地使用,但是以不同的方式提供它们各自的语义。
用迭代器(yield)做的协程的实现和示例很少。
其中一个例子是Caliburn.Micro框架,它使用这种模式进行异步GUI操作。 但它很容易推广到一般的异步代码。
MindTouch DReAM框架在Iterator模式之上实现了Coroutines,它在function上与Async / Await非常相似:
async Task Foo() { await SomeAsyncCall(); }
与
IYield Result Foo() { yield return SomeAsyncCall(); }
Result
是DReAM的Task
版本。 框架dll可以与.NET 2.0+一起使用,但要构建它需要3.5,因为我们现在使用了很多3.5语法。
微软的Bill Wagner 在MSDN杂志上写了一篇关于如何使用Visual Studio 2010中的任务并行库来实现异步行为而不添加对异步ctp的依赖的文章。
它广泛使用Task
和Task
,这也有一个额外的好处,一旦C#5出来,你的代码将准备好开始使用async
和await
。
从我的阅读来看, yield return
和await
之间的主要区别在于await
可以明确地向延续中返回一个新值。
SomeValue someValue = await GetMeSomeValue();
而对于yield return
,你必须通过引用完成同样的事情。
上述就是C#学习教程:如何在没有Async CTP的情况下实现等待分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
var asyncOperationHandle = GetMeSomeValueRequest(); yield return asyncOperationHandle; var someValue = (SomeValue)asyncOperationHandle.Result;
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/962280.html