在另一个 class C# 中取消任务
Cancel task in another class C#
我对 C# 中的 cancellationTokenSource 有疑问
public class Building {
public CancellationTokenSource BuildTokenSource;
public void StartBuilt()
{
BuildTokenSource = new CancellationTokenSource();
buildingService.buildTask = Task.Run(async () =>
{
await clock.Delay(BUILT_TIME);
}, BuildTokenSource.Token);
}
public void CancelBuilt()
{
if (BuildTokenSource != null)
{
BuildTokenSource.Cancel();
}
}
}
在另一个 class 中,想要检测任务是否像这样取消,但它不起作用。从未触发的捕获异常
public async Task<Building> GetBuildingOfUserTask()
{
double remainingTime = unitService.GetRemainingTime();
if (remainingTime <= 2000 && remainingTime > 0.0)
{
Building building = GetBuilding();
CancellationToken cancellation = building.BuildTokenSource.Token;
try
{
await buildTask;
}
catch (OperationCanceledException) when (cancellation.IsCancellationRequested)
{
return GetBuildingOfUser();
}
}
return GetBuildingOfUser();
}
有人知道为什么这不起作用,在这种情况下是解决方案吗?
我没有看到任何地方调用 CancelBuilt()
+ 你必须调用 BuildTokenSource.Token.ThrowIfCancellationRequested()
才能引发 OperationCanceledException
异常
应该在使用 cancelationToken 的异步方法之外调用 token.Cancel()
。同样使用异步方法必须调用(通常在每一步)Token.ThrowIfCancellationRequested();
我相信使用 Mediator (Mediator design pattern) 会更合适。这实际上是一个发布-订阅模型,它将在取消时发布一个事件并通知所有订阅者。
第一个class将中介实例作为参考(一个只读字段,一个属性)来发布取消事件,另一个应该相同的实例 作为参考,以便在事件实际发生时得到通知。还有一点你应该注意的是当包含'GetBuildingOfUserTask'方法的class实例被销毁时应该取消订阅。
你怎么看?
clock.Delay(BUILT_TIME)
是否有接受 CancellationToken
的重载?如果是这样,请使用它。
问题是当您取消时,如果代码已经在等待 clock.Delay(BUILT_TIME)
,clock.Delay
将不知道它需要抛出异常。
我同意 HadascokJ 的回答,我想带来更多的启发。
您有一个主要任务在 Task buildingService.buildTask
开始,它的次要任务在 await clock.Delay(BUILT_TIME);
开始
第一个任务管理 CancellationToken
但从属的任务不管理。为了更好地计算它,请将您的 clock.Delay(BUILT_TIME)
替换为 Task Task.Delay(int millisecondsDelay, CancellationToken cancellationToken);
,当然还要提供 CancelationToken
。您会看到,在这种情况下,从属任务将被取消。同时调用 void CancellationToken.CancelAfter(int millisecondsDelay)
由于您没有提供CancellationToken
给从属任务,所以主任务已经启动,主任务和从属任务都不会被取消。
另一方面,要取消从属任务的执行,为从属任务提供一些逻辑来管理 CancelationToken
到其相应的方法中,并在必要时调用 CancelationToken.ThrowIfCancellationRequested()
,抛出 OperationCanceledException
.
至少,尝试将长任务拆分成几个小任务。
我用来管理异步。任务,这些任务必须 运行 按顺序放入能够观察这些 TaskStatus
的任务队列中。为了解决这个问题,如果您需要,我在 github 有一个实现。我称之为FifoTaskQueue
我对 C# 中的 cancellationTokenSource 有疑问
public class Building {
public CancellationTokenSource BuildTokenSource;
public void StartBuilt()
{
BuildTokenSource = new CancellationTokenSource();
buildingService.buildTask = Task.Run(async () =>
{
await clock.Delay(BUILT_TIME);
}, BuildTokenSource.Token);
}
public void CancelBuilt()
{
if (BuildTokenSource != null)
{
BuildTokenSource.Cancel();
}
}
}
在另一个 class 中,想要检测任务是否像这样取消,但它不起作用。从未触发的捕获异常
public async Task<Building> GetBuildingOfUserTask()
{
double remainingTime = unitService.GetRemainingTime();
if (remainingTime <= 2000 && remainingTime > 0.0)
{
Building building = GetBuilding();
CancellationToken cancellation = building.BuildTokenSource.Token;
try
{
await buildTask;
}
catch (OperationCanceledException) when (cancellation.IsCancellationRequested)
{
return GetBuildingOfUser();
}
}
return GetBuildingOfUser();
}
有人知道为什么这不起作用,在这种情况下是解决方案吗?
我没有看到任何地方调用 CancelBuilt()
+ 你必须调用 BuildTokenSource.Token.ThrowIfCancellationRequested()
才能引发 OperationCanceledException
异常
应该在使用 cancelationToken 的异步方法之外调用 token.Cancel()
。同样使用异步方法必须调用(通常在每一步)Token.ThrowIfCancellationRequested();
我相信使用 Mediator (Mediator design pattern) 会更合适。这实际上是一个发布-订阅模型,它将在取消时发布一个事件并通知所有订阅者。
第一个class将中介实例作为参考(一个只读字段,一个属性)来发布取消事件,另一个应该相同的实例 作为参考,以便在事件实际发生时得到通知。还有一点你应该注意的是当包含'GetBuildingOfUserTask'方法的class实例被销毁时应该取消订阅。
你怎么看?
clock.Delay(BUILT_TIME)
是否有接受 CancellationToken
的重载?如果是这样,请使用它。
问题是当您取消时,如果代码已经在等待 clock.Delay(BUILT_TIME)
,clock.Delay
将不知道它需要抛出异常。
我同意 HadascokJ 的回答,我想带来更多的启发。
您有一个主要任务在 Task buildingService.buildTask
开始,它的次要任务在 await clock.Delay(BUILT_TIME);
第一个任务管理 CancellationToken
但从属的任务不管理。为了更好地计算它,请将您的 clock.Delay(BUILT_TIME)
替换为 Task Task.Delay(int millisecondsDelay, CancellationToken cancellationToken);
,当然还要提供 CancelationToken
。您会看到,在这种情况下,从属任务将被取消。同时调用 void CancellationToken.CancelAfter(int millisecondsDelay)
由于您没有提供CancellationToken
给从属任务,所以主任务已经启动,主任务和从属任务都不会被取消。
另一方面,要取消从属任务的执行,为从属任务提供一些逻辑来管理 CancelationToken
到其相应的方法中,并在必要时调用 CancelationToken.ThrowIfCancellationRequested()
,抛出 OperationCanceledException
.
至少,尝试将长任务拆分成几个小任务。
我用来管理异步。任务,这些任务必须 运行 按顺序放入能够观察这些 TaskStatus
的任务队列中。为了解决这个问题,如果您需要,我在 github 有一个实现。我称之为FifoTaskQueue