如果命令执行时间过长,请取消执行

本文关键字:取消 执行 命令 执行时间 如果 | 更新日期: 2023-09-27 18:30:11

我目前正在开发一个软件,该软件使用来自不同部门的程序集
我从这个程序集中调用一个方法,如下所示:

using (var connection = (IConnection) Factory.GetObject(typeof (IConnection)))

代码过去运行得非常好。但在最后几分钟,当我试图启动程序时,它似乎什么都没做。在调试时按下暂停键,我发现它"卡"在了上面的行
我猜他们只是在做一些维护或其他什么,但这不是重点
所以我认为如果程序没有启动,告诉用户出了什么问题会很好。像这样简单的东西

MessageBox.Show("Could not connect", "Connection Error");

然后关闭程序。我的问题是:
如何在设定的时间后终止命令的执行并跳转到其他地方
我的猜测是将它移动到一个单独的线程,然后让调用线程休眠几秒钟,然后如果还没有完成,它就会处理多余的线程。但对我来说,这似乎真的很肮脏,必须有更好的方法。

如果命令执行时间过长,请取消执行

您的问题可以分为两部分:

  1. 如何终止命令的执行

唯一的方法是中止线程但不要这样做。没有保证和安全的方法。有像Thread.Interrupt和Thread.Artrt这样的方法可以唤醒线程。但只有当线程处于WaitSleepJoin状态并且挂在托管代码中时,它们才会工作。

看起来你已经知道了。但是再一次,如果程序集中的某个东西无限地挂起了代码的执行,那么线程可能就"消失"了。所以你应该关闭这个程序是对的。

  1. 。。。跳到别的地方

好的方法是使用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();
}

其中CCD_ 2是一些CCD_。

如果没有实现本机超时,最简单的方法是用一个单独的线程来加载它,正如您所提到的。虽然这听起来很脏,但它就像(使用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.");
    }
}