Ily*_*gan 6 .net c# asynchronous async-await async-ctp
您将如何实现与Async CTP await关键字类似的功能?是否有一个简单的实现,就像await在所有情况下一样,或者是否await需要针对不同场景的不同实现?
new await关键字与现有关键字具有相似的语义yield return,因为它们都会使编译器为您生成延续样式状态机.因此,可以使用与Async CTP具有一些相同行为的迭代器来一起破解某些东西.
这是它的样子.
public class Form1 : Form
{
private void Button1_Click(object sender, EventArgs e)
{
AsyncHelper.Invoke<bool>(PerformOperation);
}
private IEnumerable<Task> PerformOperation(TaskCompletionSource<bool> 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));
}
}
Run Code Online (Sandbox Code Playgroud)
因为yield return生成IEnumerable我们的协程必须返回一个IEnumerable.所有的魔法都发生在AsyncHelper.Invoke方法中.这就是我们的协程(伪装成黑客迭代器)的原因.需要特别注意确保迭代器始终在当前同步上下文中执行,如果存在迭代器,则在尝试模拟awaitUI线程的工作方式时非常重要.它通过MoveNext同步执行第一个然后使用SynchronizationContext.Send从工作线程执行其余工作来完成此操作,工作线程也用于异步等待各个步骤.
public static class AsyncHelper
{
public static Task<T> Invoke<T>(Func<TaskCompletionSource<T>, IEnumerable<Task>> method)
{
var context = SynchronizationContext.Current;
var tcs = new TaskCompletionSource<T>();
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;
}
}
Run Code Online (Sandbox Code Playgroud)
关于TaskCompletionSource我的一点点是我尝试复制方式await可以"返回"一个值.问题是协程必须实际返回一个,IEnumerable因为它只不过是一个被黑客攻击的迭代器.所以我需要提出一种替代机制来捕获返回值.
这有一些明显的局限性,但我希望这能给你一般的想法.它还演示了CLR如何可能对于执行该协程一个通用机制await,并yield return会普遍使用,但以不同的方式提供各自的语义.
await总是涉及同样的转变 - 但这是一个非常痛苦的转变.该库的一侧await是不是太复杂,但棘手的一点是,编译器生成一个状态机的你,让连续跳回到正确的位置.
我可能会使用迭代器块(产量返回),你可以伪造类似的东西......但它会非常难看.
几周前我给出了一个关于编译器在幕后做什么的DevExpress网络研讨会 - 它显示了几个例子的反编译代码,以及解释编译器如何构建一个返回的任务,以及"awaiter"有什么做.它可能对您有用.
| 归档时间: |
|
| 查看次数: |
3603 次 |
| 最近记录: |