繁体   English   中英

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

[英]Calling an async method from a non-async method

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

输出:

开始做某事...

按任意键退出。

PrepareAwaitableTaskAction后面会比较复杂。 当此操作完成时,无论需要多长时间,我都希望通过将"Howdy ..."分配给 x,然后再分配给 y 来恢复Task (或其他框架机制)。 我真正想要做的是拦截等待的对象,处理它们,然后在我控制的稍后时间,以结果( xy )恢复到延续。 但是我在这大步上还没有走得很远,所以我试图从小处开始。

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

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

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

真的不清楚你想要实现什么,因为没有任何异步发生。 例如,这将编译并运行,但我不知道它是否是您想要的:

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);
}

这更像你追求的吗?

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

static Task<string> PrepareAwaitable(int x)
{
    return Task.Factory.StartNew<string>(() =>
    {
        return "Howdy " + x.ToString();
    });
}

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM