相当于Thread.Abort的dotnet核心 [英] dotnet core equivalent to Thread.Abort
问题描述
我有一个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 (likeThread.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, whereasThreadAbortException
was always re-raised at the end of thecatch
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屋!