如何在调用Wait时创建一个在body内部使用await的任务,该任务与同步版本的行为相同?

Dan*_*eny 5 .net c# asynchronous async-await .net-4.5

我有一些代码可以创建一个像这样做一些缓慢工作的任务:

public static Task wait1()
{
    return new Task(() =>
    {
        Console.WriteLine("Waiting...");
        Thread.Sleep(10000);
        Console.WriteLine("Done!");
    });
}
Run Code Online (Sandbox Code Playgroud)

在实际实现中,Thread.Sleep实际上将是一个Web服务调用.我想改变方法的主体可以使用await(因此它在网络访问/休眠期间不消耗线程).我的第一次尝试(基于shotgun调试编译错误)是这样的:

public static Task wait2()
{
    return new Task(async () =>
    {
        Console.WriteLine("Waiting...");
        await Task.Delay(10000);
        Console.WriteLine("Done!");
    });
}
Run Code Online (Sandbox Code Playgroud)

然而; 这个任务似乎与第一个任务的行为不一样,因为当我在它上面调用.Wait()时; 它会立即返回.

下面是一个显示差异的完整示例(控制台应用程序)(应用程序将在第二个任务启动时立即结束).

我需要做什么,以便我可以调用启动和等待任务,恰好在其中使用await代码?任务排队并稍后由代理执行,因此任务不会自动启动至关重要.

class Program
{
    static void Main(string[] args)
    {
        var w1 = wait1();
        w1.Start();
        w1.Wait(); // This waits 110 seconds

        var w2 = wait2();
        w2.Start();
        w2.Wait(); // This returns immediately
    }

    public static Task wait1()
    {
        return new Task(() =>
        {
            Console.WriteLine("Waiting...");
            Thread.Sleep(10000);
            Console.WriteLine("Done!");
        });
    }

    public static Task wait2()
    {
        return new Task(async () =>
        {
            Console.WriteLine("Waiting...");
            await Task.Delay(10000);
            Console.WriteLine("Done!");
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

Dan*_*eny 9

看来这是不可能的!在这里看到alexm的答案:

异步方法返回的任务总是很热,即它们是在运行状态下创建的.

:-(

我通过制作代理队列Func<Task>s来解决这个问题,接收任务的重载只是排队() => task.然后; 在对任务进行排队时,我会检查它是否没有运行,如果是,请启动它:

var currentTask = currentTaskFunction();
if (currentTask.Status == TaskStatus.Created)
    currentTask.Start();
Run Code Online (Sandbox Code Playgroud)

这样做似乎有点笨拙(如果这个简单的解决方法有效;为什么异步方法的原始限制总是被创建为热?),但它似乎对我有用:-)

  • 在设计功能期间,是否为冷任务提供语法的问题引起了激烈争论.显然,热门方面赢了. (4认同)
  • 实际上,这正是你想要做的.在`async`世界中,`Task`已经在运行,所以如果你想在以后启动*任务*,正确的类型是`Func <Task>`. (2认同)