监控任务完成情况

本文关键字:情况 监控任务 | 更新日期: 2023-09-27 18:22:41

我运行了几个任务,并将它们保存在一个列表中,以检查它们是否已经完成。

我发现来自async方法的任务总是显示为RanToCompletion,尽管任务本身仍在运行。

在这两种情况下,有没有办法从Task对象中获得"是否完整"信息?

下面是一个简单的测试用例,展示了这种行为。我运行两个任务,使用/不使用async方法,并在完成期间和之后检查状态。

private void test()
{
    ;
    Action actionAsync = funcAsync;
    Task taskAsync = Task.Run(actionAsync);
    Action action = func;
    Task task = Task.Run(action);
    var statusAsync = taskAsync.Status;
    var status = task.Status;
    // stati are either WaitingToRun or Running
    Thread.Sleep(TimeSpan.FromSeconds(2));
    // Now it's quite certain, that both have started
    var statusAsync2 = taskAsync.Status;
    var status2 = task.Status;
    Debug.Assert(statusAsync2 == TaskStatus.RanToCompletion);
    Debug.Assert(status2 == TaskStatus.Running);
    ;
    Thread.Sleep(TimeSpan.FromSeconds(12));
    // Now it's quite certain, that both have finished
    var statusAsync3 = taskAsync.Status;
    var status3 = task.Status;
    ;
    Debug.Assert(statusAsync3 == TaskStatus.RanToCompletion);
    Debug.Assert(status3 == TaskStatus.RanToCompletion);
}

private async void funcAsync()
{
    await Task.Delay(TimeSpan.FromSeconds(10));
}
private  void func()
{
    Thread.Sleep(TimeSpan.FromSeconds(10));
}

监控任务完成情况

我发现来自异步方法的任务总是显示为RanToCompletion,尽管任务本身仍在运行。

是的,因为您的void方法已经完成,这就是Task.Run正在调用的全部内容。如果您使用:

private async Task FuncAsync()
{
    await Task.Delay(TimeSpan.FromSeconds(10));
}

并使用Func<Task>而不是Action,那么您将调用Task.Run(Func<Task>),一切都会好起来。

简短但完整的示例:

using System;
using System.Threading;
using System.Threading.Tasks;
class Test
{
    static void Main()
    {
        Func<Task> func = FuncAsync;
        Task task = Task.Run(func);
        for (int i = 0; i < 7; i++)
        {
            Console.WriteLine(task.Status);
            Thread.Sleep(1000);
        }        
    }
    private static async Task FuncAsync()
    {
        await Task.Delay(TimeSpan.FromSeconds(5));
    }
}

输出:

WaitingForActivation
WaitingForActivation
WaitingForActivation
WaitingForActivation
WaitingForActivation
RanToCompletion
RanToCompletion

如果可能的话,尽量避免编写void异步方法。它们基本上应该只用于事件处理程序。