5 秒后取消长时间运行的任务未完成 [英] Cancel long running Task after 5 seconds when not finished
问题描述
我创建了一个创建 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屋!