C#任务工厂超时
我必须在线程中执行一个长进程操作,并通过将结果返回给函数继续。这是我的密码:C#任务工厂超时,c#,timeout,task,factory,C#,Timeout,Task,Factory,我必须在线程中执行一个长进程操作,并通过将结果返回给函数继续。这是我的密码: Task<ProductEventArgs>.Factory.StartNew(() => { try { // long operation which return new ProductEventArgs with a list of product } catch (Exception e)
Task<ProductEventArgs>.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());
如果达到超时时间。
无法使用wait/async。
非常感谢 您可以并行运行
任务。延迟(超时)
任务,并检查首先完成的任务(Task.whenay()
在这种情况下非常方便):
public void FetchProduct(TimeSpan超时)
{
var fetchTask=Task.Factory.StartNew(
() =>
{
尝试
{
//返回带有产品列表的新ProductEventArgs的长操作
}
捕获(例外e)
{
返回新的ProductEventArgs(){E=E};
}
});
任务结果任务;
如果(超时!=超时。无限期)
{
var timeoutTask=Task.Delay(超时);
resultTask=Task.WhenAny(resultTask,timeoutTask)。是否继续(
t=>
{
//完成的任务是
if(t.Result==fetchTask)
{
返回fetchTask.Result;
}
其他的
{
返回新的ProductEventArgs(){E=new TimeoutException()};
}
});
}
其他的
{
resultTask=fetchTask;
}
resultTask.ContinueWith(x=>handleResult(x.Result),TaskScheduler.FromCurrentSynchronizationContext());
}
请注意,此解决方案没有任何取消逻辑,即使超时,长时间运行的任务仍将运行。此代码执行您在此处表达的操作:
var timeout = TimeSpan.FromSeconds(5);
var actualTask = new Task<ProductEventArgs>(() =>
{
var longRunningTask = new Task<ProductEventArgs>(() =>
{
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
var timeout=TimeSpan.FromSeconds(5);
var actualTask=新任务(()=>
{
var longRunningTask=新任务(()=>
{
尝试
{
Thread.Sleep(TimeSpan.FromSeconds(10));//模拟长时间运行的计算
返回新的ProductEventArgs();
}
捕获(例外e)
{
返回新的ProductEventArgs(){E=E};
}
},TaskCreationOptions.LongRunning);
longRunningTask.Start();
if(longRunningTask.Wait(timeout))返回longRunningTask.Result;
返回新的ProductEventArgs(){E=新异常(“超时”)};
});
actualTask.Start();
实际任务。等待();
Console.WriteLine(“{0}”,actualTask.Result.E);//处理E
如您所见,longRunningTask
是使用TaskCreationOptions.LongRunning
选项创建的。这样,它将有一个专用的线程
来执行它,并且不会因为占用线程太长时间而干扰线程池
的正常行为,这是UI等其他东西所需要的这对于长时间运行的任务很重要
注意:然后您可以使用
ContinueWith
处理实际任务
,但我想在这里表达其本质。您应该使用取消令牌
s:
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
var token = cts.Token;
Task<ProductEventArgs>.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());
var cts=new CancellationTokenSource(TimeSpan.FromSeconds(10));
var-token=cts.token;
Task.Factory.StartNew(()=>
{
尝试
{
//偶尔,执行以下命令行:
token.ThrowIfCancellationRequested();
}
捕获(操作取消异常)
{
返回新的ProductEventArgs(){E=new Exception(“timeout”)};
}
捕获(例外e)
{
返回新的ProductEventArgs(){E=E};
}
}).ContinueWith((x)=>handleResult(x.Result),TaskScheduler.FromCurrentSynchronizationContext());
您可以将返回的任务对象用于StartNew方法,然后使用user Wait方法来确定超时时间
Task<ProductEventArgs> task = Task<ProductEventArgs>.Factory.StartNew(() => {...});
if (!Task.Wait(new TimeSpan(0,0,1,0)) // wait for 1 minute
{
// throw exception or something else if timeout
}
Task Task=Task.Factory.StartNew(()=>{…});
if(!Task.Wait(new TimeSpan(0,0,1,0))//等待1分钟
{
//如果超时,则抛出异常或其他内容
}
只需在主任务(代理)中启动另一个任务:
Task.Factory.StartNew(()=>
{
//返回字符串结果
var tsk=新任务(()=>{return veryiimportantthingstodo();});
尝试
{
tsk.Start();
如果(!tsk.等待(5000))
抛出新的TimeoutException();
返回tsk.Result;
}
捕获(超时异常)
{
//Jabba Dabba Doooooohh
}
返回“”;
}).ContinueWith((o)=>字符串结果=o.result));
我完全同意这一点。希望OP能做到这一点——我的回答是基于(可能是鲁莽的)假设,OP正在用他的控制调用一些不支持超时或取消的代码,所以我假设他不能这样做。我希望他能在您的代码中,我只需要将令牌作为startnew方法的第二个参数,对吗?因为不是你写的。如果我这样做了,例如timestan为0秒,我在handle result(x.result)上有一个aggregateException。谢谢,在您的情况下,您不应该将取消令牌
传递给开始新建
。如果您这样做(如您所观察到的),则已取消的CancellationToken
实际上会在任务开始之前取消任务。但您不希望任务完成取消,因此这不是您想要的行为。您的代码将在.Net 4.5及更高版本上运行,因为在.Net 4.0上,CancellationTokenSource只有默认构造函数。爱您:-*我对C有点陌生,对线程管理有更多了解,您让我开心!
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
var token = cts.Token;
Task<ProductEventArgs>.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());
Task<ProductEventArgs> task = Task<ProductEventArgs>.Factory.StartNew(() => {...});
if (!Task.Wait(new TimeSpan(0,0,1,0)) // wait for 1 minute
{
// throw exception or something else if timeout
}
Task.Factory.StartNew(() =>
{
// returns a string result
var tsk = new Task<string>(() => { return VeryImportantThingsToDo(); });
try
{
tsk.Start();
if (!tsk.Wait(5000))
throw new TimeoutException();
return tsk.Result;
}
catch (TimeoutException)
{
// Jabba Dabba Doooooooohhhhhh
}
return "<unknown>";
}).ContinueWith((o) => string result = o.Result));