如何等待Task启动

本文关键字:Task 启动 等待 何等待 | 更新日期: 2023-09-27 18:17:32

如何等待任务启动?以下代码失败:

var asyncmethod = ...a Task<TReturn>, with .Start() called on it...;
int waitcounter = 0;
while (!asyncmethod.Wait(1000))
{
    waitcounter++;
    Log("waiting very long...");
}
ret = asyncmethod.Result;

asyncmethod.Wait(1000)按预期等待1秒,但任务处于WaitingToRun状态,并且在Wait()ing时永远不会开始运行。另一方面,当. result被调用时,它将开始运行。如何让它运行而不调用。result ?

如何等待Task启动

任务处于WaitingToRun状态,并且在Wait()ing

时不会开始运行。

当一个任务处于WaitingToRun状态时,这意味着它已经准备好开始运行,只是在等待它的调度上下文可用,所以它可以被调度和运行(正如我在我的博客中所描述的)。

由于Wait(1000)完成后任务仍然处于此状态,那么假定任务正在等待调用线程使用的调度上下文,因此在该线程空闲之前无法调度

任务。Result可以触发任务内联并执行任务,但显然Wait()不能。

.Result.Wait()都将允许任务内联,但是.Wait(x)当然不能,因为它必须遵守超时。

然而,.Result.Wait()都不能保证内联——在编写可靠的代码时记住这一点很重要。

代码不应该中断,不管任务是被安排在"当前"还是一个单独的线程上。

这是一个极其难以满足的要求。你确定你需要这个吗?

最简单的解决方案是异步等待:
Task<T> asyncmethod = ...;
int waitcounter = 0;
while (await Task.WhenAny(Task.Delay(1000), asyncmethod) != asyncmethod)
{
  waitcounter++;
  Log("waiting very long...");
}
ret = await asyncmethod;

等待任务完成,使用:

asyncmethod.Start();
asyncmethod.Wait();  // not needed in most cases
// but if used, the task is completed at this point.
var ret = asyncmethod.Result; // automatically waits for the task to be completed

但基本上,等待是不必要的,除非你有理由这样做。从Task<TResult>.Result -docs:

此属性的get访问器确保异步操作完成后返回。曾经的结果计算是可用的,它被存储并将返回立即调用Result。(从msdn)

不太确定为什么要这样做,但这可以在不阻塞调用线程的情况下实现使用Task.IsCompletedTask.Delay:

public async Task FooAsync()
{
    var waitCounter = -1;
    var task = Task.Run(() => { });
    do
    {
        waitCounter++;
        await Task.Delay(1000);
    }
    while (!task.IsCompleted)
}

如果Task需要超过1000ms才能完成,则此代码段将调用Log一次。

    private async static void StartTask()
    {
        Task<object> asyncmethod = ... ;
        LogDurationTooLong(asyncmethod, 1000);
        var result = await asyncmethod;
    }
    /// <summary>
    /// Logs if a task takes too long to complete.
    /// </summary>
    /// <param name="asyncmethod">The task to reference.</param>
    /// <param name="duration">The duration after which a log entry is made.</param>
    private async static void LogDurationTooLong(Task asyncmethod, int duration)
    {
        Task completedTask = await Task.WhenAny(Task.Delay(duration), asyncmethod);
        if (completedTask != asyncmethod)
        {
            Log("waiting very long...");
        }
    }