为Func< Task>切换新的Task(()=> {}). [英] Switch new Task(()=>{ }) for Func<Task>

查看:184
本文介绍了为Func< Task>切换新的Task(()=> {}).的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在对其他问题之一的答案中,有人告诉我new Task(() => { })的使用不是是一个正常的用例.建议我改用Func<Task>.我已经尝试过进行这项工作,但是我似乎无法弄清楚. (而不是将其拖到评论中,我在这里问一个单独的问题.)

In an answer to one of my other questions, I was told that use of new Task(() => { }) is not something that is a normal use case. I was advised to use Func<Task> instead. I have tried to make that work, but I can't seem to figure it out. (Rather than drag it out in the comments, I am asking a separate question here.)

我的具体情况是,我需要任务在声明后就无法立即启动,并且能够稍后再等待它.

My specific scenario is that I need the Task to not start right when it is declared and to be able to wait for it later.

这是使用new Task(() => { })的LinqPad示例. 注意:这很好用! (除了使用new Task.)

Here is a LinqPad example using new Task(() => { }). NOTE: This works perfectly! (Except that it uses new Task.)

static async void Main(string[] args)
{
    // Line that I need to swap to a Func<Task> somehow.
    // note that this is "cold" not started task  
    Task startupDone = new Task(() => { });

    var runTask = DoStuff(() =>
    {
        //+++ This is where we want to task to "start"
        startupDone.Start();
    });

    //+++ Here we wait for the task to possibly start and finish. Or timeout.
    // Note that this times out at 1000ms even if "blocking = 10000" below.
    var didStartup = startupDone.Wait(1000);

    Console.WriteLine(!didStartup ? "Startup Timed Out" : "Startup Finished");

    await runTask;

    Console.Read();
}

public static async Task DoStuff(Action action)
{
    // Swap to 1000 to simulate starting up blocking
    var blocking = 1; //1000;
    await Task.Delay(500 + blocking);
    action();
    // Do the rest of the stuff...
    await Task.Delay(1000);
}

我尝试将第二行与:

Func<Task> startupDone = new Func<Task>(async () => { });

但随后注释中带有+++的行将无法正常工作.

But then the lines below the comments with +++ in them don't work right.

我用startupDone.Invoke()交换了startupDone.Start().

但是startupDone.Wait需要任务.仅在lambda中返回.我不确定如何访问lambda之外的任务,因此可以Wait进行操作.

But startupDone.Wait needs the task. Which is only returned in the lambda. I am not sure how to get access to the task outside the lambda so I can Wait for it.

如何使用Func<Task>并在我的代码的一部分中启动Wait并在我的代码的另一部分中对其进行Wait?(就像我可以使用new Task(() => { })一样)

How can use a Func<Task> and start it in one part of my code and do a Wait for it in another part of my code? (Like I can with new Task(() => { })).

推荐答案

您发布的代码无法重构为使用Func<Task>而不是冷任务,因为需要await任务的方法( Main方法)与控制任务创建/启动(DoStuff方法的lambda参数)的方法不同.在这种情况下,这可以使Task构造函数的使用合法,这取决于是否有合理的理由将启动任务委托给lambda的设计决策.在此特定示例中,startupDone用作同步原语,以表示已满足条件并且程序可以继续.通过使用专门的同步原语,例如

The code you posted cannot be refactored to make use of a Func<Task> instead of a cold task, because the method that needs to await the task (the Main method) is not the same method that controls the creation/starting of the task (the lambda parameter of the DoStuff method). This could make the use of the Task constructor legitimate in this case, depending on whether the design decision to delegate the starting of the task to a lambda is justified. In this particular example the startupDone is used as a synchronization primitive, to signal that a condition has been met and the program can continue. This could be achieved equally well by using a specialized synchronization primitive, like for example a SemaphoreSlim:

static async Task Main(string[] args)
{
    var startupSemaphore = new SemaphoreSlim(0);
    Task runTask = RunAsync(startupSemaphore);
    bool startupFinished = await startupSemaphore.WaitAsync(1000);
    Console.WriteLine(startupFinished ? "Startup Finished" : "Startup Timed Out");
    await runTask;
}

public static async Task RunAsync(SemaphoreSlim startupSemaphore)
{
    await Task.Delay(500);
    startupSemaphore.Release(); // Signal that the startup is done
    await Task.Delay(1000);
}

我认为

在这种情况下,使用SemaphoreSlim更有意义,并且可以使代码的意图更加清晰.它还允许异步地await带有超时 WaitAsync(Int32) ,这不是您可以直接从Task获得的内容(

In my opinion using a SemaphoreSlim is more meaningful in this case, and makes the intent of the code clearer. It also allows to await asynchronously the signal with a timeout WaitAsync(Int32), which is not something that you get from a Task out of the box (it is doable though).

在某些情况下,使用冷任务可能很诱人,但是当您在一两个月后重新访问代码时,您会感到困惑,因为不得不处理可能会或可能不会遇到的任务是多么罕见和意外已经开始了.

Using cold tasks may be tempting in some cases, but when you revisit your code after a month or two you'll find yourself confused, because of how rare and unexpected is to have to deal with tasks that may or may have not been started yet.

这篇关于为Func&lt; Task&gt;切换新的Task(()=&gt; {}).的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆