从非异步方法调用异步方法
本文关键字:异步方法 调用 | 更新日期: 2023-09-27 18:17:22
我尝试的以下代码的每个变体都不起作用-无论是DoSomething() : void
和按写的方式调用,还是DoSomething() : Task
和用TaskEx.RunEx()
调用,一些涉及.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"
。
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();
});
}
}
输出:start DoSomething…
按任意键退出。
PrepareAwaitable
's Task
's Action
后面会更复杂。当这个动作完成时,无论需要多长时间,我都希望Task
(或其他框架机制)通过将"Howdy ..."
分配给x,然后再分配给y来恢复。我真正想做的是拦截等待的对象,处理它们,并在稍后我控制的时间内恢复到具有结果(x
和y
)的延续。但是我还没有迈出那么大的一步,所以我试着从更小的开始
首先,阅读基于任务的异步模式文档。在My Documents'Microsoft Visual Studio Async CTP'Documentation
下。本文档描述了如何设计可被await
自然使用的api。
其次,要认识到Task
类和相关api的几个方面不再真正适用于新的异步世界。Task
最初是作为TPL的核心编写的。事实证明,它非常适合异步编程,因此微软使用它而不是创建一个新的"承诺"。类。但是许多方法是保留的,由TPL使用,但不需要异步编程。
要回答这个名义上的问题,在当前的异步CTP中,混合同步和异步代码并不是很简单。我编写了一个库,其中包含一个Task.WaitAndUnwrapException
扩展方法,这使得从同步代码调用异步代码变得容易。你可能对我的AsyncContext
课也感兴趣,这使得"按任意键"引发不必要的。
您返回的任务尚未开始(即,它们是"冷"任务);尝试用以下代码替换PrepareAwaitable代码:
static Task<string> PrepareAwaitable(int x)
{
return Task.Factory.StartNew<string>(() =>
{
return "Howdy " + x.ToString();
});
}
这真的不清楚你想要实现什么,因为没有异步发生。例如,这将编译并运行,但我不知道这是否是您想要的:
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
一个警告,因为它没有异步;没有await表达式。整个程序同步执行。PrepareAwaitable
的另一个替代实现:
static Task<string> PrepareAwaitable(int x)
{
return TaskEx.Run(() => "Howdy " + x);
}
那更像你想要的吗?
添加GetAwaiter().GetResult()
后,您的异步任务应该工作。但是为了消除诸如"……"之类的错误。而不是在null action"任务上调用,您只需让Task<IHttpActionResult>
返回Ok(true)而不是Ok()。它为我修复了getreresult()问题!