繁体   English   中英

任务内联和Task.Wait

[英]Task inlining and Task.Wait

我刚刚意识到,当我从任务中启动任务并调用Task.Wait ,新任务将不会被内联,而调用Task.Result将始终内联任务。

当我们使用RAII模式(在ExecuteWithCancel实现)包装我们的任务时,内联将重用已分配的资源,因此更可取。

但我们有时想等一段时间并在此之后取消任务。 等待代码如下所示:

using (var cts = new CancellationTokenSource())
{
   // Task scheduler decides whether to execute synchronous or asynchronous
   var task = new Task<TResult>(() => ExecuteWithCancel<TResult>(cts.Token, nameOfTaskPerformer, arguments), cts.Token)
   if (timeout==TimeSpan.Zero || task.Wait(timeout)) // this creates an all or nothing timeout
      return task.Result;
   cts.Cancel();
   throw new TimeoutException("");
}

当超时是TimeSpan.Zero ,任务被内联,否则它总是使用另一个线程。

有没有一种简单的方法来重新设计此代码以使用内联和等待/超时?

相当确定这是不可能的。 假设您在线程A上运行以下代码:

var task = Task.Factory.StartNew(() => Thread.Sleep(Timeout.Infinite));
task.Wait(5000);

如果任务内联,线程A将无限期阻塞 - 超时后它将如何唤醒? 查看参考源(Task.cs),我们可以确切地看到:

internal bool InternalWait(int millisecondsTimeout, CancellationToken cancellationToken) 
{
   ...
   // we will attempt inline execution only if an infinite wait was requested 
   // Inline execution doesn't make sense for finite timeouts and if a cancellation token was specified
   // because we don't know how long the task delegate will take. 
   if (millisecondsTimeout == Timeout.Infinite && !cancellationToken.CanBeCanceled &&
       WrappedTryRunInline() && IsCompleted) 
   {
       returnValue = true; 
   } 
   else
   { 
       returnValue = CompletedEvent.Wait(millisecondsTimeout, cancellationToken);
   }

根据您的问题,为了从内联有限超时中受益,您必须在任务本身内部实现超时逻辑,也许像这样:

ExecuteWithCancel<TResult>(cts.Token, TimeSpan timeout, nameOfTaskPerformer, arguments)

然后使用常规的Wait() (或Result )。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM