相当于Thread.Abort的dotnet核心 [英] dotnet core equivalent to Thread.Abort

查看:470
本文介绍了相当于Thread.Abort的dotnet核心的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Service抽象.每个服务都有自己的WorkItem. WorkItem能够以一些数据开始.该服务限制了WorkItem的执行时间.假设一个工作项最多可能需要60秒.此后,Service应该将其杀死.

I have a Service abstraction. Each service has it own WorkItem. WorkItem able to start with some data. The service is limiting the excution time of WorkItem. Let's say that a single workitem can takes up to 60 seconds. After this, the Service should kill it.

此代码从标准.NET Framework迁移,我创建了一个Thread对象,该对象运行Start(model)方法.然后代码是这样的:

This code migrated from the Standard .NET Framework, I created a Thread object which run the Start(model) method. Then the code was something like:

Thread t = new Thread(workItem.Start, model);
t.start();
if (!t.Join(TimeSpan.FromSeconds(60)))
    t.Abort();

Thread.Abort正在为正在运行的线程注入异常,这导致它立即停止.

The Thread.Abort was injecting an exception for the running thread, which lead it for immediately stop.

现在,我将代码移到了dotnet core -您可能知道,当您致电Thread.Abort()时,会收到以下消息:

Now, I moved the code to dotnet core - as you may know, when you calling Thread.Abort() your getting the following message:

System.PlatformNotSupportedException: Thread abort is not supported on this platform.
   at System.Threading.Thread.Abort()
   at ...

目标

我想将WorkItem的执行时间限制为特定的时间.请注意,如果您像这样运行代码行,则此限制也应起作用:

The Goal

I want to limit the execution time of the WorkItem to specific amount of time. Note that this limitation should work also if you running code line like this:

Thread.sleep(61000); // 61 seconds. should be stop after 60 seconds.

进度

在dotnet核心世界中,似乎要使用Task相关解决方案.因此,我想使用CancellationToken.但是似乎无法观看隐身"事件并立即停止.我看到的示例使用的是while (!canceled)循环,该循环无法停止长时间的操作(例如Thread.Sleep(1000000).

Progress

On the dotnet core world, it's seems like it's going to the Task related solution. So, I thought to use CancellationToken. But its seems like its impossible to watch the "Cacneled" event and stop immediately. The examples I saw are using while (!canceled) loops, which cant stop long operations (like Thread.Sleep(1000000).

如何正确处理?

我编写了此示例代码:

public static bool ExecuteWithTimeLimit(TimeSpan timeSpan, Action codeBlock)
{
    try
    {
        Task task = Task.Factory.StartNew(() => codeBlock());
        if (!task.Wait(timeSpan))
        {
            // ABORT HERE!
            Console.WriteLine("Time exceeded. Aborted!");
        }
        return task.IsCompleted;
    }
    catch (AggregateException ae)
    {
        throw ae.InnerExceptions[0];
    }
}

这个Main文件:

public static void Main(string[] args)
{
    bool Completed = ExecuteWithTimeLimit(TimeSpan.FromMilliseconds(2000), () =>
    {
        Console.WriteLine("start");
        Thread.Sleep(3000);
        Console.WriteLine("end");
    });

    Console.WriteLine($"Completed={Completed}");
    Console.ReadLine();
}

预期:结束"不会打印到屏幕上.实际:结束"打印.有没有其他选择可以杀死Task?

Expected: "end" wont be printed to the screen. Actual: "end" printed. Is there any alternative that can kill a Task?

推荐答案

在不中止的情况下,唯一的解决方法是对轮询请求进行足够的轮询,以便在您提到的所有while (!canceled)解决方案之后.

Without aborting the only solution is to poll the cancellation request often enough so after all the while (!canceled) solution you mentioned.

我看到的示例正在使用while (!canceled)循环,该循环无法停止长时间的操作(例如Thread.Sleep(1000000).

The examples I saw are using while (!canceled) loops, which cant stop long operations (like Thread.Sleep(1000000).

这只是部分正确.例如,可以这样重写以响应:

This is just partially true. For example, this can be re-written like this to be responsive:

 var timeout = TimeSpan.FromSeconds(60);
 var stopwatch = new Stopwatch();
 stopwatch.Start();

 while (!cancelToken.IsCancellationRequested
  && stopwatch.ElapsedMilliseconds < timeout)
{
    Thread.Sleep(10);
}

当然,并不是每个任务都可以很容易地重新编写以轮询取消操作.如果您处于深层次的通话链中,那么检查每个级别的取消可能会很痛苦.因此,您还可以使用CancellationToken.ThrowIfCancellationRequested方法,如果有取消请求,该方法将抛出OperationCanceledException.通常,我通常不会只为自己抛出异常并将其用于控制​​流,但取消是可以证明其合理性的领域之一.

Of course, not every task can be easily re-written to poll the cancellation like this. If you are in a deep call chain it can be a pain to check the cancellation at every level. For that reason you can also use the CancellationToken.ThrowIfCancellationRequested method, which will throw an OperationCanceledException if there was a cancel request. I usually tend to not throwing an exception just for myself and using it for control flow but cancellation is one of the areas where it can be justified.

Abort相比,此解决方案当然具有一些局限性:

This is solution has of course some limitations compared to Abort:

  • 您将无法取消不支持取消且无法重构的第三方程序
  • OperationCanceledException可以很容易地吞下,而ThreadAbortException总是在catch块的末尾重新引发,因此即使包含通用的catch块,第3部分库也有可能被中止. /li>
  • You will not able to cancel 3rd party routines, which don't support cancellation and you cannot refactor them
  • The OperationCanceledException can be swallowed easily, whereas ThreadAbortException was always re-raised at the end of the catch blocks so a 3rd part library could be aborted by a good chance even if contained general catch blocks.

更新:

如果您有足够的信心/绝望,可以使用 ThreadEx.Abort 方法,该方法通过反射调用Thread.AbortInternal.尽管不能保证它将是.NET Core中的长期解决方案.

If you are confident/desperate enough you can use the ThreadEx.Abort method, which calls the Thread.AbortInternal by reflection. Though it is not guaranteed it will be a long-living solution in .NET Core.

尽管我完全不同意将Thread.Abort作废,因为它是关闭您没有影响的例程的好机会,否则我也必须避免流产不惜一切代价,因为它可能具有讨厌的副作用.如果您是整个代码库的作者,那么总是可以避免的.

Though I don't completely agree with making Thread.Abort obsolete as it was a good last-chance tool for shutting down routines on which you didn't have influence otherwise, I'm also at the side abortion must be avoided at all costs as it can have nasty side effects. If you are the author of the whole code base it can be always avoided.

更新2:

此后似乎已删除AbortInternal.至少当前的.NET Core源代码不包含这种方法.

It seems that AbortInternal has been removed since then. At least current .NET Core source does not contain such a method.

这篇关于相当于Thread.Abort的dotnet核心的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆