标签: taskcompletionsource

什么时候应该使用TaskCompletionSource <T>?

AFAIK,它所知道的是,在某些时候,它SetResultSetException方法被调用以Task<T>通过其Task属性完成暴露.

换句话说,它充当a Task<TResult>及其完成的生产者.

我在这里看到这个例子:

如果我需要一种方法来异步执行Func并有一个Task来表示该操作.

public static Task<T> RunAsync<T>(Func<T> function) 
{ 
    if (function == null) throw new ArgumentNullException(“function”); 
    var tcs = new TaskCompletionSource<T>(); 
    ThreadPool.QueueUserWorkItem(_ => 
    { 
        try 
        {  
            T result = function(); 
            tcs.SetResult(result);  
        } 
        catch(Exception exc) { tcs.SetException(exc); } 
    }); 
    return tcs.Task; 
}
Run Code Online (Sandbox Code Playgroud)

可以使用*如果我没有Task.Factory.StartNew- 但我确实Task.Factory.StartNew.

题:

可有人请举例相关的情景解释直接TaskCompletionSource 而不是一个假想中,我没有的情况 Task.Factory.StartNew

.net c# .net-4.0 task-parallel-library taskcompletionsource

188
推荐指数
7
解决办法
8万
查看次数

超时使用TaskCompletionSource实现的异步方法

我有一个blackbox对象,它暴露了一个异步操作的方法,并在操作完成时触发一个事件.我已经将它包装到一个Task<OpResult> BlackBoxOperationAysnc()使用TaskCompletionSource 的方法中 - 效果很好.

但是,在那个异步包装器中,如果在给定的超时后没有收到事件,我想管理用超时错误完成异步调用.目前我使用计时器管理它:

public Task<OpResult> BlackBoxOperationAysnc() {
    var tcs = new TaskCompletionSource<TestResult>();   
    const int timeoutMs = 20000;
    Timer timer = new Timer(_ => tcs.TrySetResult(OpResult.Timeout),
                            null, timeoutMs, Timeout.Infinite);

    EventHandler<EndOpEventArgs> eventHandler = (sender, args) => {
        ...
        tcs.TrySetResult(OpResult.BlarBlar);
    }
    blackBox.EndAsyncOpEvent += eventHandler;
    blackBox.StartAsyncOp();
    return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud)

这是管理超时的唯一方法吗?有没有设置我自己的计时器 - 我在TaskCompletionSource中看不到任何超时?

c# asynchronous timeout async-await taskcompletionsource

19
推荐指数
1
解决办法
1万
查看次数

任务FromResult与TaskCompletionSource SetResult

有关功能和含义的区别是什么

TaskCompletionSource + SetResult vs Task + FromResult

在SendAsync方法?

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
    if (request.RequestUri.Scheme != Uri.UriSchemeHttps)
    {
        var response = new HttpResponseMessage(HttpStatusCode.Forbidden) {ReasonPhrase = "HTTPS Required"};
        var taskCompletionSource = new TaskCompletionSource<HttpResponseMessage>();
        taskCompletionSource.SetResult(response);
        return taskCompletionSource.Task;
    }
    return base.SendAsync(request, cancellationToken);
}

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
    if (!request.RequestUri.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase))
    {
        HttpResponseMessage reply = request.CreateErrorResponse(HttpStatusCode.BadRequest, "HTTPS is required for security reason.");
        return Task.FromResult(reply);
    }

    return base.SendAsync(request, cancellationToken);
}
Run Code Online (Sandbox Code Playgroud)

c# task-parallel-library async-await asp.net-web-api taskcompletionsource

19
推荐指数
2
解决办法
5051
查看次数

如何组合TaskCompletionSource和CancellationTokenSource?

我有这样的代码(在这里简化)等待完成任务:

var task_completion_source = new TaskCompletionSource<bool>();
observable.Subscribe(b => 
   { 
      if (b) 
          task_completion_source.SetResult(true); 
   });
await task_completion_source.Task;    
Run Code Online (Sandbox Code Playgroud)

这个想法是订阅并等待true布尔流.这完成了"任务",我可以继续前进await.

但是我想取消 - 但不是订阅,而是等待.我想传递取消令牌(不知何故),task_completion_source所以当我取消令牌源时,await将继续前进.

怎么做?

更新:CancellationTokenSource这个代码是外部的,我这里所有的都是来自它的令牌.

c# asynchronous async-await cancellationtokensource taskcompletionsource

17
推荐指数
2
解决办法
7617
查看次数

如何使用TaskCompletionSource.SetException保留等待行为?

(这是对这个问题的新尝试,现在更好地证明了这个问题.)

假设我们有一个错误的任务(var faultedTask = Task.Run(() => { throw new Exception("test"); });),我们等待它.await将解压缩AggregateException并抛出基础异常.它会抛出faultedTask.Exception.InnerExceptions.First().

根据源代码,ThrowForNonSuccess它将通过执行任何存储ExceptionDispatchInfo来执行此操作,可能是为了保留良好的堆栈跟踪.AggregateException如果没有,它将不会打开包装ExceptionDispatchInfo.

这个事实本身是令人惊讶的,因为我的文档指出,第一异常始终抛出:https://msdn.microsoft.com/en-us/library/hh156528.aspx?f=255&MSPPError=-2147217396事实证明,await即可AggregateException但是,抛出,这是没有记录的行为.

当我们想要创建代理任务并设置它的异常时,这就成了一个问题:

var proxyTcs = new TaskCompletionSource<object>();
proxyTcs.SetException(faultedTask.Exception);
await proxyTcs.Task;
Run Code Online (Sandbox Code Playgroud)

这将引发AggregateExceptionawait faultedTask;将抛出测试异常.

如何创建我可以随意完成的代理任务,这将反映原始任务的异常行为?

最初的行为是:

  1. await 将抛出第一个内部异常.
  2. 所有例外情况仍可通过Task.Exception.InnerExceptions.(这个问题的早期版本遗漏了这个要求.)

这是一个总结了调查结果的测试:

[TestMethod]
public void ExceptionAwait()
{
    ExceptionAwaitAsync().Wait();
}

static async Task ExceptionAwaitAsync()
{
    //Task has multiple exceptions.
    var faultedTask = Task.WhenAll(Task.Run(() …
Run Code Online (Sandbox Code Playgroud)

.net c# task-parallel-library async-await taskcompletionsource

16
推荐指数
1
解决办法
1876
查看次数

TaskCompletionSource抛出"尝试将任务转换为已完成的最终状态"

我想用来TaskCompletionSource包装MyService哪个是简单的服务:

public static Task<string> ProcessAsync(MyService service, int parameter)
{
    var tcs = new TaskCompletionSource<string>();
    //Every time ProccessAsync is called this assigns to Completed!
    service.Completed += (sender, e)=>{ tcs.SetResult(e.Result); };   
    service.RunAsync(parameter);
    return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud)

这段代码第一次运行良好.但是我第二ProcessAsync简单地Completed再次调用事件处理程序(service每次使用相同的变量),因此它将执行两次!并且它第二次抛出此异常:

在已经完成时尝试转换任务最终状态

我不确定,我应该tcs像这样声明一个类级变量:

TaskCompletionSource<string> tcs;

public static Task<string> ProccessAsync(MyService service, int parameter)
{
    tcs = new TaskCompletionSource<string>();
    service.Completed -= completedHandler; 
    service.Completed += completedHandler;
    return tcs.Task;    
}

private void completedHandler(object sender, CustomEventArg e)
{ …
Run Code Online (Sandbox Code Playgroud)

.net c# asynchronous async-await taskcompletionsource

15
推荐指数
2
解决办法
1万
查看次数

使用TaskCompletionSource的TaskCreationOptions的目的是什么?

对于我的内心运作方式,我有些不清楚TaskCompletionSource<>.

Task<>使用the 创建一个简单的时候Factory,我希望这个任务在一个线程池中排队,除非我指定TaskCreationOptions.LongRunning,它将在一个新的线程中运行.

我的理解TaskCompletionSource是,我负责在任务结束或失败时触发,并且我完全控制如何管理线程.然而,ctor TaskCompletionSource允许我指定一个TaskCreationOptions,这让我感到困惑,因为我期望Scheduler无法处理任务本身.

TaskCreationOptions在一个上下文中的目的是TaskCompletionSource<>什么?

这是一个使用示例:

public Task<WebResponse> Download(string url)
{
    TaskCompletionSource<WebResponse> tcs = 
    new TaskCompletionSource<WebResponse>(TaskCreationOptions.LongRunning);

    var client = (HttpWebRequest)HttpWebRequest.Create(url);
    var async = client.BeginGetResponse(o =>
      {
          try
          {
              WebResponse resp = client.EndGetResponse(o);
              tcs.SetResult(resp);
          }
          catch (Exception ex)
          {
              tcs.SetException(ex);
          }
      }, null);


    return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud)

c# task-parallel-library taskcompletionsource

12
推荐指数
1
解决办法
961
查看次数

如何使用timout取消TaskCompletionSource

我有一个函数,我使用await关键字异步调用:

public Task<StatePropertyEx> RequestStateForEntity(EntityKey entity, string propName)
{
    var tcs = new TaskCompletionSource<StateInfo>();
    try
    {
        var propInstance = BuildCacheKey(entity, propName);
        StateCacheItem cacheItem;
        if (_stateCache.TryGetValue(propInstance, out cacheItem))
        {
            tcs.SetResult( new StateInfo (cacheItem.State.Name, cacheItem.State.Value) );
            return tcs.Task;
        }

        //state not found in local cache so save the tcs for later and request the state
        var cacheKey = BuildCacheKey(entity, propName);
       _stateRequestItemList.TryAdd(cacheKey, new StateRequestItem(entity, propName, tcs));

        _evtClient.SubmitStateRequest(entity, propName);

        return tcs.Task;
    }
    catch (Exception ex)
    {
        tcs.SetException(ex);
        return tcs.Task;
    }
}
Run Code Online (Sandbox Code Playgroud)

该函数查看它是否具有所需的信息,如果有,则返回它.如果它没有详细信息,它会发送一个最终应该作为事件发出的请求.此时,我的代码(未显示)找到存储的TaskCompletionSource项,设置结果并返回它.这一切都运行正常但我现在被要求考虑一种情况,当我通过"_evtClient.SubmitStateRequest(entity,propName);"行请求状态时,可能永远不会返回回复.我需要实现某种超时机制,以便我可以取消TCS任务,以便函数调用者可以正常失败.我一直在寻找SO和互联网,找不到任何看起来正确的东西.我现在不确定是否需要以不同的方式重构上述代码.任何人都可以建议或指向类似的情况?

调用上述函数的代码可以在单击中调用它,如下所示:

var stateProperty …
Run Code Online (Sandbox Code Playgroud)

c# async-await taskcompletionsource

10
推荐指数
1
解决办法
7283
查看次数

为什么我的TCS没有等待?

async关键字导致CIL改变(即使有方法内部没有的await),但它主要是允许await存在.

但我没想到会发生以下情况:

static void Main(string[] args)
{
    Task t = Go();
    t.Wait();
}

static async Task Go()
{
    Console.WriteLine(1);
    await AAA(3000);
    Console.WriteLine(2);
}


static  Task<object> AAA(int a) // <--- No `async`
{
    TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
    Task.Delay(a).ContinueWith(b => tcs.SetResult(null));
    return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud)

这个印刷品:

1
(wait)
2
Run Code Online (Sandbox Code Playgroud)

但如果我改变

static  Task<object> AAA(int a) 
Run Code Online (Sandbox Code Playgroud)

static async  Task<object> AAA(int a) 
Run Code Online (Sandbox Code Playgroud)

它打印:

1
2
(no wait)
Run Code Online (Sandbox Code Playgroud)

为什么我没有看到延迟?TCS仅在三秒后解决.同时,任务没有得到解决,应该等待.

.net c# task-parallel-library async-await taskcompletionsource

9
推荐指数
2
解决办法
756
查看次数

可以检测.NET库代码中的不受控制的取消吗?

我发现我无法区分受控/合作与"不受控制"的任务/代表取消,而无需检查特定任务或代表背后的来源.

具体来说,我总是假设当OperationCanceledException从"低级操作"中捕获抛出时,如果引用的令牌无法与当前操作的令牌匹配,那么它应该被解释为失败/错误.这是它放弃(退出)的"低级操作"的声明,但不是因为你要求它这样做.

不幸的是,TaskCompletionSource无法关联一个CancellationToken作为取消的原因.因此,没有内置调度程序支持的任何任务无法传达其取消的原因,并且可能错误地将合作取消误报为错误.

更新:由于.NET 4.6 TaskCompletionSource 可以关联起来CancellationToken ,如果新的过载SetCanceledTrySetCanceled使用.

例如以下内容

public Task ShouldHaveBeenAsynchronous(Action userDelegate, CancellationToken ct)
{
    var tcs = new TaskCompletionSource<object>();

    try
    {
      userDelegate();
      tcs.SetResult(null);   // Indicate completion
    }
    catch (OperationCanceledException ex)
    {
      if (ex.CancellationToken == ct)
        tcs.SetCanceled(); // Need to pass ct here, but can't
      else
        tcs.SetException(ex);
    }
    catch (Exception ex)
    {
      tcs.SetException(ex);
    }

    return tcs.Task;
}

private void OtherSide()
{
    var cts …
Run Code Online (Sandbox Code Playgroud)

c# asynchronous task task-parallel-library taskcompletionsource

6
推荐指数
1
解决办法
1009
查看次数