C#任务工厂超时
我必须在一个线程中执行一个长进程操作,并继续将结果返回给一个函数。 这是我的代码:
Task.Factory.StartNew(() => { try { // long operation which return new ProductEventArgs with a list of product } catch (Exception e) { return new ProductEventArgs() { E = e }; } }).ContinueWith((x) => handleResult(x.Result), TaskScheduler.FromCurrentSynchronizationContext());
问题实际上我没有超时。 我想放一个计时器,以便返回这样的东西:
new ProductEventArgs() { E = new Exception("timeout") };
如果达到超时。 不能使用await / async。 非常感谢 !
此代码执行您在此处表达的内容:
var timeout = TimeSpan.FromSeconds(5); var actualTask = new Task(() => { var longRunningTask = new Task (() => { try { Thread.Sleep(TimeSpan.FromSeconds(10)); // simulates the long running computation return new ProductEventArgs(); } catch (Exception e) { return new ProductEventArgs() { E = e }; } }, TaskCreationOptions.LongRunning); longRunningTask.Start(); if (longRunningTask.Wait(timeout)) return longRunningTask.Result; return new ProductEventArgs() { E = new Exception("timed out") }; }); actualTask.Start(); actualTask.Wait(); Console.WriteLine("{0}", actualTask.Result.E); // handling E
如您所见,使用TaskCreationOptions.LongRunning
选项创建了TaskCreationOptions.LongRunning
。 这样它就会有一个专用的Thread
来执行它,并且不会通过占用一个线程太长时间来干扰ThreadPool
的正常行为 – 这将是其他东西所需要的,比如UI。 这对于长时间运行的任务非常重要 。
注意:然后你可以用ContinueWith
处理actualTask
,但我想在这里表达精华。
你应该使用CancellationToken
:
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); var token = cts.Token; Task.Factory.StartNew(() => { try { // occasionally, execute this line: token.ThrowIfCancellationRequested(); } catch (OperationCanceledException) { return new ProductEventArgs() { E = new Exception("timeout") }; } catch (Exception e) { return new ProductEventArgs() { E = e }; } }).ContinueWith((x) => handleResult(x.Result), TaskScheduler.FromCurrentSynchronizationContext());
您可以将返回的任务对象用于StartNew方法,然后使用用户Wait方法来确定超时。
Task task = Task .Factory.StartNew(() => {...}); if (!Task.Wait(new TimeSpan(0,0,1,0)) // wait for 1 minute { // throw exception or something else if timeout }
您可以并行运行Task.Delay(timeout)
任务并检查首先完成的任务Task.WhenAny()
在这种情况下Task.WhenAny()
非常方便):
public void FetchProduct(TimeSpan timeout) { var fetchTask = Task.Factory.StartNew( () => { try { // long operation which return new ProductEventArgs with a list of product } catch(Exception e) { return new ProductEventArgs() { E = e }; } }); Task resultTask; if(timeout != Timeout.InfiniteTimeSpan) { var timeoutTask = Task.Delay(timeout); resultTask = Task.WhenAny(resultTask, timeoutTask).ContinueWith ( t => { // completed task is the result of WhenAny if(t.Result == fetchTask) { return fetchTask.Result; } else { return new ProductEventArgs() { E = new TimeoutException() }; } }); } else { resultTask = fetchTask; } resultTask.ContinueWith(x => handleResult(x.Result), TaskScheduler.FromCurrentSynchronizationContext()); }
请注意,此解决方案没有任何取消逻辑,即使超时,您的长时间运行任务仍将继续运行。
只需在主要任务(代理)中启动另一个任务:
Task.Factory.StartNew(() => { // returns a string result var tsk = new Task(() => { return VeryImportantThingsToDo(); }); try { tsk.Start(); if (!tsk.Wait(5000)) throw new TimeoutException(); return tsk.Result; } catch (TimeoutException) { // Jabba Dabba Doooooooohhhhhh } return ""; }).ContinueWith((o) => string result = o.Result));