6

我尝试的以下代码的每个变体都不起作用 - 无论是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();
        });
    }
}

输出:

开始做某事...

按任意键退出。

PrepareAwaitable'sTask后面Action会更复杂。当此操作完成时,无论花费多长时间,我都希望Task(或其他框架机制)通过分配给 x 来恢复"Howdy ...",然后再分配给 y。我真正想做的是拦截等待的对象,处理它们,并在稍后我控制的某个时间,以结果(xy)继续继续。但我在这大步上还没有走得太远,所以我试图从小处着手。

4

4 回答 4

11

首先,阅读基于任务的异步模式文档。它在My Documents\Microsoft Visual Studio Async CTP\Documentation. 本文档描述了如何设计可自然使用的 API await

其次,要意识到Task类和相关 API 的某些方面不再真正适用于新的异步世界。Task最初是作为 TPL 的核心编写的。结果证明它非常适合异步编程,所以微软使用它而不是创建一个新的“Promise”类。但是许多方法是保留的,TPL 使用但异步编程不需要。

为了回答名义上的问题,在当前的异步 CTP 中混合同步和异步代码并不是很简单。我编写了一个包含扩展方法的库Task.WaitAndUnwrapException,它可以轻松地从同步代码中调用异步代码。您可能也对我的AsyncContext感兴趣,这使得“按任意键”提示变得不必要。

于 2011-12-09T01:12:44.260 回答
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);
}

这更像是你所追求的吗?

于 2011-12-08T23:03:15.853 回答
5

您返回的任务尚未开始(即它们是“冷”任务);尝试用以下代码替换 PrepareAwaitable 代码:

static Task<string> PrepareAwaitable(int x)
{
    return Task.Factory.StartNew<string>(() =>
    {
        return "Howdy " + x.ToString();
    });
}
于 2011-12-08T23:03:57.750 回答
-1

GetAwaiter().GetResult()在你的异步任务应该工作之后添加。但是为了消除诸如“......不要在具有空操作的任务上调用”之类的错误,您只需Task<IHttpActionResult>返回 Ok(true) 而不是 Ok()。它为我解决了 GetResult() 问题!

于 2021-03-24T09:31:22.083 回答