5 秒后取消长时间运行的任务未完成 [英] Cancel long running Task after 5 seconds when not finished

查看:46
本文介绍了5 秒后取消长时间运行的任务未完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个创建 XML 字符串的任务.该任务可以持续数秒.当 5 秒后任务未完成时,我想顺利"取消任务并继续编写其余的 XML.所以我在我的任务中内置了取消.但是虽然我在日志中看到以下消息:

I have created a task which creates an XML string. The task can last multiple seconds. When the task isn't finished after 5 seconds, I want to cancel the Task 'smootly' and continue with writing the rest of the XML. So I built in cancellation inside my task. But although I see the following message in the Log:

  • ProcessInformationTask 超时

我也在我的日志中看到了这一行

I also see this line in my log

添加进程信息耗时 10001 ms

Adding the process information took 10001 ms

我想知道为什么会发生这种情况,因为我想在 5 秒后取消任务(如果没有完成).所以我希望任务最多持续 5 秒.我该如何解决这个问题?可能取消设置不正确?

I wonder why this can happen because I want to cancel the Task after 5 seconds (if not finished). So I expect the task to last 5 seconds max. How can I solve this? Probably the cancelation isn't setup properly?

我调用任务的代码

string additionalInformation = null;
var contextInfo = new StringBuilder();

var xmlWriterSettings = new XmlWriterSettings()
{
    OmitXmlDeclaration = true,
    ConformanceLevel = ConformanceLevel.Fragment
};

var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;

using (XmlWriter xmlWriter = XmlWriter.Create(contextInfo, xmlWriterSettings))
{
    try
    {
        xmlWriter.WriteStartElement("AdditionalInformation");

        //Write xml (not long running)

        var watch = System.Diagnostics.Stopwatch.StartNew();
        string processInformation = AddProcessesInformation(xmlWriterSettings);
        watch.Stop();
        var elapsedMs = watch.ElapsedMilliseconds;
        Log.Info("Adding the process information took : " + elapsedMs + " ms");

        if (!string.IsNullOrEmpty(processInformation))
        {
            xmlWriter.WriteRaw(processInformation);
        }

        //Write xml (not long running)

        xmlWriter.WriteEndElement();

        additionalInformation = contextInfo.ToString();
    }

    catch (Exception e)
    {
        Log.Info("An exception occured during writing the additional information: " + e.Message);
        return false;
    }

    return true;
} 

任务方法

private static string AddProcessesInformation(XmlWriterSettings xmlWriterSettings)
    {
        var tokenSource = new CancellationTokenSource();
        var token = tokenSource.Token;
        var contextInfo = new StringBuilder();

        var processInformationTask = Task<string>.Factory.StartNew(() =>
        {
            if (token.IsCancellationRequested)
            {
                Log.Info("Cancellation request for the ProcessInformationTask");
            }

            Thread.Sleep(10000);

            return "Ran without problems'";

        }, token);

        if (!processInformationTask.Wait(5000, token))
        {
            Log.Info("ProcessInformationTask timed out");
            tokenSource.Cancel();
        }

        return processInformationTask?.Result;
    }

推荐答案

我认为您应该在方法的每个步骤之后检查是否多次请求取消.以下是使用 for 循环的示例:

I think you should check if cancellation is requested multiple Times, after each step in your method. Here is example using for loop:

    private static string AddProcessesInformation(XmlWriterSettings xmlWriterSettings)
    {
        var tokenSource = new CancellationTokenSource();
        var token = tokenSource.Token;
        var contextInfo = new StringBuilder();

        var processInformationTask = Task<string>.Factory.StartNew(() =>
        {               
            for(int i = 0; i < 10; i++)
            {
                if (token.IsCancellationRequested)
                {
                    Console.WriteLine("Cancellation request for the ProcessInformationTask");
                    return string.Empty;
                }
                Thread.Sleep(1000);
            }

            return "Ran without problems'";

        }, token);

        if (!processInformationTask.Wait(5000, token))
        {
            Console.WriteLine("ProcessInformationTask timed out");
            tokenSource.Cancel();
        }

        return processInformationTask?.Result;
    }

如果在任务方法内部调用其他方法,则可以将取消令牌传递给它们并在内部使用方法token.ThrowIfCancellationRequested().

If inside task method you call other methods, you can pass cancellation token to them and use method token.ThrowIfCancellationRequested() inside.

        var processInformationTask = Task<string>.Factory.StartNew(() =>
        {
            try
            {
                Method1(token);
                Thread.Sleep(1000);
                Method2(token);
                Thread.Sleep(1000);
            }
            catch(OperationCanceledException ex)
            {
                return string.Empty;
            }
            return "Ran without problems'";

        }, token);


    private static void Method1(CancellationToken token)
    {
        token.ThrowIfCancellationRequested();
        // do more work
    }

这篇关于5 秒后取消长时间运行的任务未完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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