从非异步方法调用异步方法

时间:2011-12-08 22:46:05

标签: c# async-ctp

我尝试的以下代码的每个变体都不起作用 - 无论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 ...")继续。但是我在这个重要的步骤上并没有走得太远,所以我试图从小做起。

4 个答案:

答案 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() 问题!