- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
考虑以下代码:
CancellationTokenSource cts0 = new CancellationTokenSource(), cts1 = new CancellationTokenSource();
try
{
var task = Task.Run(() => { throw new OperationCanceledException("123", cts0.Token); }, cts1.Token);
task.Wait();
}
catch (AggregateException ae) { Console.WriteLine(ae.InnerException); }
由于MSDN任务应处于 Faulted
状态,因为它的 token 与异常的 token 不匹配(并且 IsCancellationRequested
为 false
):
If the token's IsCancellationRequested property returns false or if the exception's token does not match the Task's token, the OperationCanceledException is treated like a normal exception, causing the Task to transition to the Faulted state.
当我使用 .NET 4.5.2 在控制台应用程序中启动此代码时,我得到处于 Canceled
状态的任务(聚合异常包含未知的 TaskCanceledExeption
,而不是原始的)。并且原始异常的所有信息都丢失了(消息、内部异常、自定义数据)。
我还注意到,在 OperationCanceledException
情况下,Task.Wait
的行为不同于 await task
。
try { Task.Run(() => { throw new InvalidOperationException("123"); }).Wait(); } // 1
catch (AggregateException ae) { Console.WriteLine(ae.InnerException); }
try { await Task.Run(() => { throw new InvalidOperationException("123"); }); } // 2
catch (InvalidOperationException ex) { Console.WriteLine(ex); }
try { Task.Run(() => { throw new OperationCanceledException("123"); }).Wait(); } // 3
catch (AggregateException ae) { Console.WriteLine(ae.InnerException); }
try { await Task.Run(() => { throw new OperationCanceledException("123"); }); } // 4
catch (OperationCanceledException ex) { Console.WriteLine(ex); }
案例 1
和 2
产生几乎相同的结果(仅在 StackTrace
中不同),但是当我将异常更改为 OperationCanceledException
,然后我得到非常不同的结果:一个未知的 TaskCanceledException
如果 3
没有原始数据,预期的 OpeartionCanceledException
如果 4
包含所有原始数据(消息等)。
所以问题是:MSDN 是否包含不正确的信息?还是 .NET 中的错误?或者也许只是我不明白什么?
最佳答案
这是一个错误。 Task.Run
引擎盖下调用 Task<Task>.Factory.StartNew
.此内部任务正在获得正确的故障状态。包装任务不是。
您可以通过调用来解决此错误
Task.Factory.StartNew(() => { throw new OperationCanceledException("123", cts0.Token); }, cts1.Token, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
但是,您将失去 Task.Run
的其他功能这是展开。参见:
Task.Run vs Task.Factory.StartNew
更多详情:
这是 Task.Run
的代码你看到它正在创建一个包装 UnwrapPromise
(源自 Task<TResult>
:
public static Task Run(Func<Task> function, CancellationToken cancellationToken)
{
// Check arguments
if (function == null) throw new ArgumentNullException("function");
Contract.EndContractBlock();
cancellationToken.ThrowIfSourceDisposed();
// Short-circuit if we are given a pre-canceled token
if (cancellationToken.IsCancellationRequested)
return Task.FromCancellation(cancellationToken);
// Kick off initial Task, which will call the user-supplied function and yield a Task.
Task<Task> task1 = Task<Task>.Factory.StartNew(function, cancellationToken, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
// Create a promise-style Task to be used as a proxy for the operation
// Set lookForOce == true so that unwrap logic can be on the lookout for OCEs thrown as faults from task1, to support in-delegate cancellation.
UnwrapPromise<VoidTaskResult> promise = new UnwrapPromise<VoidTaskResult>(task1, lookForOce: true);
return promise;
}
它调用的任务构造函数不带取消标记(因此它不知道内部任务的取消标记)。请注意,它会创建一个默认的 CancellationToken。这是它调用的 ctor:
internal Task(object state, TaskCreationOptions creationOptions, bool promiseStyle)
{
Contract.Assert(promiseStyle, "Promise CTOR: promiseStyle was false");
// Check the creationOptions. We only allow the AttachedToParent option to be specified for promise tasks.
if ((creationOptions & ~TaskCreationOptions.AttachedToParent) != 0)
{
throw new ArgumentOutOfRangeException("creationOptions");
}
// m_parent is readonly, and so must be set in the constructor.
// Only set a parent if AttachedToParent is specified.
if ((creationOptions & TaskCreationOptions.AttachedToParent) != 0)
m_parent = Task.InternalCurrent;
TaskConstructorCore(null, state, default(CancellationToken), creationOptions, InternalTaskOptions.PromiseTask, null);
}
外部任务(UnwrapPromise
添加了一个延续)。继续检查内部任务。在内部任务出错的情况下,它认为找到一个 OperationCanceledException 作为指示取消(不管匹配的 token )。下面是 UnwrapPromise<TResult>.TrySetFromTask
(下面也是显示调用位置的调用堆栈)。注意故障状态:
private bool TrySetFromTask(Task task, bool lookForOce)
{
Contract.Requires(task != null && task.IsCompleted, "TrySetFromTask: Expected task to have completed.");
bool result = false;
switch (task.Status)
{
case TaskStatus.Canceled:
result = TrySetCanceled(task.CancellationToken, task.GetCancellationExceptionDispatchInfo());
break;
case TaskStatus.Faulted:
var edis = task.GetExceptionDispatchInfos();
ExceptionDispatchInfo oceEdi;
OperationCanceledException oce;
if (lookForOce && edis.Count > 0 &&
(oceEdi = edis[0]) != null &&
(oce = oceEdi.SourceException as OperationCanceledException) != null)
{
result = TrySetCanceled(oce.CancellationToken, oceEdi);
}
else
{
result = TrySetException(edis);
}
break;
case TaskStatus.RanToCompletion:
var taskTResult = task as Task<TResult>;
result = TrySetResult(taskTResult != null ? taskTResult.Result : default(TResult));
break;
}
return result;
}
调用栈:
mscorlib.dll!System.Threading.Tasks.Task<System.Threading.Tasks.VoidTaskResult>.TrySetCanceled(System.Threading.CancellationToken tokenToRecord, object cancellationException) Line 645 C#
mscorlib.dll!System.Threading.Tasks.UnwrapPromise<System.Threading.Tasks.VoidTaskResult>.TrySetFromTask(System.Threading.Tasks.Task task, bool lookForOce) Line 6988 + 0x9f bytes C#
mscorlib.dll!System.Threading.Tasks.UnwrapPromise<System.Threading.Tasks.VoidTaskResult>.ProcessCompletedOuterTask(System.Threading.Tasks.Task task) Line 6956 + 0xe bytes C#
mscorlib.dll!System.Threading.Tasks.UnwrapPromise<System.Threading.Tasks.VoidTaskResult>.InvokeCore(System.Threading.Tasks.Task completingTask) Line 6910 + 0x7 bytes C#
mscorlib.dll!System.Threading.Tasks.UnwrapPromise<System.Threading.Tasks.VoidTaskResult>.Invoke(System.Threading.Tasks.Task completingTask) Line 6891 + 0x9 bytes C#
mscorlib.dll!System.Threading.Tasks.Task.FinishContinuations() Line 3571 C#
mscorlib.dll!System.Threading.Tasks.Task.FinishStageThree() Line 2323 + 0x7 bytes C#
mscorlib.dll!System.Threading.Tasks.Task.FinishStageTwo() Line 2294 + 0x7 bytes C#
mscorlib.dll!System.Threading.Tasks.Task.Finish(bool bUserDelegateExecuted) Line 2233 C#
mscorlib.dll!System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref System.Threading.Tasks.Task currentTaskSlot) Line 2785 + 0xc bytes C#
mscorlib.dll!System.Threading.Tasks.Task.ExecuteEntry(bool bPreventDoubleExecution) Line 2728 C#
mscorlib.dll!System.Threading.Tasks.Task.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() Line 2664 + 0x7 bytes C#
mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch() Line 829 C#
mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() Line 1170 + 0x5 bytes C#
它注意到 OperationCanceledException 并调用 TrySetCanceled 将任务置于已取消状态。
旁白:
还有一点要注意,当你开始使用async
方法,实际上没有办法用 async
注册取消 token 方法。因此,在异步方法中遇到的任何 OperationCancelledException 都被视为取消。看 Associate a CancellationToken with an async method's Task
关于c# - Task.Wait 在 OperationCanceledException 情况下的意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25488357/
我正在尝试向 URL 发出异步 Web 请求,该请求将在请求时间过长时返回。我正在使用 F# 异步工作流和 System.Net.Http 库来执行此操作。 但是,我无法在 async 中捕获 Sys
我得到一个TaskCanceledException: 然后我将此异常作为 Exception 传递给另一个方法。如果我检查类型 if (ex.GetType() == typeof(Operatio
我的同事玩过 TPL 和任务取消。他向我展示了以下代码: var cancellationToken = cts.Token; var task = Task.Run(() => { whil
我有一个 Azure Function (.net 6.0),它从服务总线接收消息。 99% 的消息处理得很好,但时不时地我会在 Application Insights 中收到 System.Ope
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 6 年前。 Improve this qu
我正在实现一个 Parallel.ForEach 循环来做一些工作,但由于未处理的异常,我遇到了一个问题,而我认为我处理了取消。 为了尝试解决问题,我在 winform 中做了一个简单的测试设置。它有
我有一些代码要从 .NET 4.5 的可爱 async 和 await 关键字降级到 .NET 4.0。我正在使用 ContinueWith 创建一个类似于 await 工作方式的延续。 基本上,我的
以下代码创建了一个被取消的任务。 await 表达式(案例 1)抛出 System.OperationCanceledException 而同步 Wait()(案例 2)抛出 System.Threa
OperationCanceledException 和 TaskCanceledException 有什么区别?如果我使用 .NET 4.5 并使用 async/await 关键字,我应该寻找哪个?
我正在使用一个支持取消的异步 api,我正在向该 api 传递一个 CancellationToken实例。像往常一样,如果在传递的 token 上请求取消,我正在调用的 api 将抛出 Operat
我有来自“.NET Framework 并行编程示例”的以下代码 MSDN当我试图在 Debug模式下取消猴子的遗传生成时,我在 token.ThrowIfCancellationRequested(
当用户加载页面时,它会发出一个或多个 ajax 请求,这些请求会命中 ASP.NET Web API 2 Controller 。如果用户导航到另一个页面,在这些 ajax 请求完成之前,浏览器会取消
我正在遵循示例代码 here了解异步任务。我修改了代码以编写任务工作与主要工作的一些输出。输出将如下所示: 我注意到,如果我删除 Wait() 调用,程序运行相同,只是我无法捕获任务取消时抛出的异常。
首先,请原谅我的英语。我将在 Task.WhenAny 之后的附加代码中进行简要说明,我期望的是五个任务中至少有三个将被取消,但都圆满结束。当任务被取消时,SemaphoreSlim.WaitAsyn
我有一个长时间运行的操作,我想在 5 秒后取消。不幸的是,无法轮询 IsCancellationRequested(长话短说)。 我使用下面的代码在取消回调中抛出一个 OperationCancele
考虑以下代码: CancellationTokenSource cts0 = new CancellationTokenSource(), cts1 = new CancellationTokenSo
我试图允许取消 Parallel.ForEach 循环。根据this MSDN article ,这是可能的,我正在按照他们的编码进行操作。 // Tokens for cancellation Pa
我正在使用 BlockingCollection 来实现任务调度程序,基本上: public class DedicatedThreadScheduler : TaskScheduler, IDisp
我正在使用(坦率地说很棒)BlockingCollection键入大量多线程的高性能应用。 集合的吞吐量很大,在微观层面上它的性能很高。但是,对于每个“批处理”,它将始终通过标记取消 token 来结
我使用 Async.Catch 来处理异步工作流抛出的异常: work |> Async.Catch |> Async.RunSynchronously |> fun x -> match x wit
我是一名优秀的程序员,十分优秀!