我尝试的以下代码的每个变体都不起作用 - 无论DoSomething() : void
是否被调用,或DoSomething() : Task
并且使用TaskEx.RunEx()
调用,有些尝试涉及{{ 1}}。发现的错误包括:.GetAwaiter().GetResult()
,"Start may not be called on a task with null action"
和"RunSynchronously may not be called on a task unbound to a delegate"
。
"The task has not yet completed"
输出:
启动DoSomething ......
按任意键退出。
class Program
{
static void Main(string[] args) // Starting from a non-async method
{
DoSomething();
Console.WriteLine("Press any key to quit.");
Console.ReadKey();
}
static async void DoSomething()
{
Console.WriteLine("Starting DoSomething ...");
var x = await PrepareAwaitable(1);
Console.WriteLine("::" + x);
var y = await PrepareAwaitable(2);
Console.WriteLine("::" + y);
}
static Task<string> PrepareAwaitable(int id)
{
return new Task<string>(() =>
{
return "Howdy " + id.ToString();
});
}
}
PrepareAwaitable
的{{1}}稍后会更复杂。当此操作完成时,无论多长时间,我都希望通过将Task
分配给x,然后再分配给y来恢复Action
(或其他框架机制)。我真正想要做的是拦截等待的对象,处理它们,并在稍后我控制的时候,继续使用结果(Task
和"Howdy ..."
)继续。但是我在这个重要的步骤上并没有走得太远,所以我试图从小做起。
答案 0 :(得分:11)
首先,阅读基于任务的异步模式文档。它位于My Documents\Microsoft Visual Studio Async CTP\Documentation
之下。本文档描述了如何设计await
自然消耗的API。
其次,要意识到Task
类和相关API的几个方面在新的异步世界中不再适用。 Task
最初是作为TPL的核心编写的。事实证明它非常适合异步编程,因此Microsoft使用它而不是创建一个新的“Promise”类。但是许多方法都是保留,由TPL使用但不需要异步编程。
要回答这个标题问题,使用当前的异步CTP混合同步和异步代码并不是很简单。我写了a library,其中包含Task.WaitAndUnwrapException
扩展方法,可以轻松地从同步代码中调用异步代码。您可能也对我的AsyncContext
class感兴趣,这使得“按任意键”提示不必要。
答案 1 :(得分:5)
目前还不清楚你想要实现什么,因为没有任何异步发生。例如,这将编译并运行,但我不知道它是否是您想要的:
using System;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
DoSomething();
Console.WriteLine("Press any key to quit.");
Console.ReadKey();
}
static async void DoSomething()
{
Console.WriteLine("Starting DoSomething ...");
var x = await PrepareAwaitable(1);
Console.WriteLine("::" + x);
var y = await PrepareAwaitable(2);
Console.WriteLine("::" + y);
}
static async Task<string> PrepareAwaitable(int x)
{
return "Howdy " + x;
}
}
请注意,这会给PrepareAwaitable
发出警告,因为它没有异步;没有“等待”表达。整个程序同步执行。 PrepareAwaitable
的另一种替代实现:
static Task<string> PrepareAwaitable(int x)
{
return TaskEx.Run(() => "Howdy " + x);
}
这更像你的追求吗?
答案 2 :(得分:5)
您返回的任务尚未开始(即,他们是“冷”的任务);尝试使用以下内容替换PrepareAwaitable代码:
static Task<string> PrepareAwaitable(int x)
{
return Task.Factory.StartNew<string>(() =>
{
return "Howdy " + x.ToString();
});
}
答案 3 :(得分:-1)
在异步任务应该工作后添加 GetAwaiter().GetResult()
。但是为了消除诸如“...不要在具有空操作的任务上调用”之类的错误,您只需让 Task<IHttpActionResult>
返回 Ok(true) 而不是 Ok()。
它为我解决了 GetResult() 问题!