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));