![](/img/trans.png)
[英]Call a method and cancel it and return to the calling method if it takes too long
[英]Cancel execution of command if it takes too long
我目前正在开发一款使用来自不同部门的程序集的软件。
我从这个程序集中调用一个方法,如下所示:
using (var connection = (IConnection) Factory.GetObject(typeof (IConnection)))
代码过去工作得很好。 但是在最后几分钟,当我尝试启动我的程序时,它似乎什么也没做。 调试时按暂停键显示它“卡在”了上面的行。
我的猜测是他们只是在做一些维护或其他事情,但这不是这里的重点。
因此,如果程序未启动,我最好告诉用户出了什么问题。 像简单的东西
MessageBox.Show("Could not connect", "Connection Error");
然后关闭程序。 我的问题是:
如何在设定的时间后终止命令的执行并跳转到其他地方?
我的猜测是将它移动到一个单独的线程,然后让调用线程休眠几秒钟,然后如果它尚未完成,它将处理额外的线程。 但这对我来说真的很脏,必须有更好的方法。
您的问题可以分为两部分:
唯一的方法是中止线程。 但是不要这样做。 没有保证和安全的方法。 Thread.Interrupt 和 Thread.Abort 等方法可以唤醒线程。 但是只有当线程处于 WaitSleepJoin 状态并且它挂在托管代码中时它们才会工作。
好像你已经知道了。 但是再一次,如果程序集内部的某些东西无限地挂起代码的执行,那么线程可能已经“消失”了。 所以你是对的,该程序应该关闭。
好的方法是使用 TPL 和异步模型。 这是一个扩展方法来包装任何任务并在超时后过期。
public static async Task TimeoutAfter(this Task task, int millisecondsTimeout)
{
if (task == await Task.WhenAny(task, Task.Delay(millisecondsTimeout)))
await task;
else
throw new TimeoutException();
}
然后使用它
try
{
using (var result = await Task.Run(() => (IConnection)Factory.GetObject(typeof(IConnection))).TimeoutAfter(1000))
{
...
}
}
catch (TimeoutException ex)
{
//timeout
}
在这里您可以找到更多信息
一种无需额外库或扩展方法的简单方法:
using ( var task = new Task<IConnection>( () => Factory.GetObject( typeof( IConnection ) ) ) )
{
task.Start();
if( !task.Wait( timeoutMilliseconds ) )
{
throw new TimeoutException();
}
IConnection result = task.Result;
}
Task.Wait
做你想做的,因为如果它返回 false 你可以抛出异常(任务没有及时完成。)
如果您有一个不返回任何内容的 Action,它会更简单:
if ( !Task.Run( action ).Wait( timeoutMilliseconds ) )
{
throw new TimeoutException();
}
其中action
是一些Action
或 lambda。
如您所述,如果未实现本机超时,最简单的方法是使用一个单独的线程来加载它。 虽然这听起来很脏,但它就像(使用 Rx)一样简单:
Task<IConnection> connectionTask = Observable.Start(() => Factory.GetObject(typeof (IConnection)), Scheduler.Default).Timeout(TimeSpan.FromSeconds(20)).ToTask());
using (var connection = connectionTask.Result)
{
...
}
如果您不希望它在线程池上运行,您可以调整Scheduler
。 如果Factory.GetObject
调用时间超过 20 秒,它将抛出TimeoutException
。
您可以使用CancellationTokenSource设置操作超时
var timeoutCts = new CancellationTokenSource();
try
{
timeoutCts.CancelAfter(300000); // Cancel after 5 minutes
// ... run your long term operation
}
catch (OperationCanceledException ex)
{
// Handle the timeout
}
请参阅 Microsoft 的此文档
using System;
using System.Threading.Tasks;
public class Example
{
public static void Main()
{
Task t = Task.Run(() =>
{
Random rnd = new Random();
long sum = 0;
int n = 5000000;
for (int ctr = 1; ctr <= n; ctr++)
{
int number = rnd.Next(0, 101);
sum += number;
}
Console.WriteLine("Total: {0:N0}", sum);
Console.WriteLine("Mean: {0:N2}", sum / n);
Console.WriteLine("N: {0:N0}", n);
});
TimeSpan ts = TimeSpan.FromMilliseconds(150);
if (!t.Wait(ts))
Console.WriteLine("The timeout interval elapsed.");
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.