繁体   English   中英

如何在一段时间后停止异步任务

[英]How to stop async Task after a certain period of time

我试图在一段时间后停止 C# 中的任务。

对于我的代码: Task.Delay().Wait() 应该只代表 Task 所做的一些工作。

我的代码:

public static void Main()
{
    Console.WriteLine("starting app");
    try
    {
        Console.WriteLine("before");
        DoStuff(1000);
        Console.WriteLine("after");
    }
    catch
    {
        Console.WriteLine("TIMEOUT");
    }
    Console.WriteLine("Main finished wait 5 sec now");
    Task.Delay(10000).Wait();
    Console.WriteLine("Closing app now");
}

public static async Task DoStuff(int time)
{
    Task real = Task.Run(()=>
    {
        Task.Delay(2000).Wait();
        Console.WriteLine("Task Running");
        Task.Delay(2000).Wait();
        Console.WriteLine("still running");
        Task.Delay(2000).Wait();
        Console.WriteLine("Not dead yet");
        Task.Delay(1000).Wait();
        Console.WriteLine("Task done");
        Task.Delay(5000);
    });

    bool success = real.Wait(time);
    if ( success )
    {
        Console.WriteLine("Task finished in time");
        await real;
    }
    else
    {
        Console.WriteLine("Task did not finish");
        real.Dispose();
        throw new TimeoutException("The task took too long");
    }
}

我已经尝试使用取消令牌,但我没有循环来检查每次迭代的令牌。 所以我尝试用Task.Wait(time) ,我得到了正确的消息,但是在使用Task.Dispose()方法后任务并没有停止。 我得到以下 output:

在此处输入图像描述

所以我得到了当前的 output 但任务继续在后面运行..关于如何解决这个问题的任何想法?

首先:永远不要Wait()任务(除非你知道他们已经完成); 使用await 至于超时:可以让CancellationTokenSource延迟后超时,如下。

请注意,取消令牌不会中断代码 - 您(或其他代码,如Task.Delay的情况)需要检查取消(例如ThrowIfCancellationRequested() ),或者您需要使用Register(...)添加一个回调,当它被取消时将被调用

using System;
using System.Threading;
using System.Threading.Tasks;

static class P
{

    public static async Task Main()
    {
        Console.WriteLine("starting app");
        try
        {

            Console.WriteLine("before");
            await DoStuffAsync(1000);
            Console.WriteLine("after");
        }
        catch
        {
            Console.WriteLine("TIMEOUT");
        }
        Console.WriteLine("Main finished wait 5 sec now");
        await Task.Delay(5000);
        Console.WriteLine("Closing app now");
    }
    public static async Task DoStuffAsync(int time)
    {
        using var cts = new CancellationTokenSource(time); // assuming here that "time" is milliseconds
        Task real = Task.Run(async () =>
        {
            await Task.Delay(2000, cts.Token);
            Console.WriteLine("Task Running");
            await Task.Delay(2000, cts.Token);
            Console.WriteLine("still running");
            await Task.Delay(2000, cts.Token);
            Console.WriteLine("Not dead yet");
            await Task.Delay(2000, cts.Token);
            Console.WriteLine("Task done");
            await Task.Delay(2000, cts.Token);
        });

        bool success;
        try
        {
            await real;
            success = true;
        }
        catch (OperationCanceledException)
        {
            success = false;
        }

        if (success)
        {
            Console.WriteLine("Task finished in time");
        }
        else
        {
            Console.WriteLine("Task tool too long");
        }
    }
}

请注意,您也可以将取消令牌传递给Task.Run ,但这只是在执行回调之前进行检查 - 而且通常不会有明显的延迟,所以......通常不值得。

附加说明:如果您想确定取消的确切内容(即OperationCanceledException来自cts ):

catch (OperationCanceledException cancel) when (cancel.CancellationToken == cts.Token)

暂无
暂无

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

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