【问题标题】:Convert TaskCompletionSource to Task.FromResult<TResult>?将 TaskCompletionSource 转换为 Task.FromResult<TResult>?
【发布时间】:2014-04-01 19:25:55
【问题描述】:

我有这个异步启动方法的简单代码。它使用TCS包装任务代码。

Task<int> DoWork()
{
    var source = new TaskCompletionSource <int>();
    Thread.Sleep(220);
    source.SetResult(9999999);
    return source.Task;
}

void Main()
{
    Console.WriteLine(1);

    var t1=Task.Factory.StartNew(()=>DoWork());
    t1.ContinueWith(_=>Console.WriteLine ("doing something different "));
    t1.ContinueWith(_=>Console.WriteLine ("finished , value is ="+_.Result.Result));

    Console.WriteLine(2);
    Console.ReadLine();
}

输出:

1
2
doing somethign different  //those last 2 lines can be swapped
finished , value is =9999999

但是现在,我想将其转换为使用Task.FromResult&lt;TResult&gt;

这是poorly documented,所以我想知道如何将上面的代码转换为使用Task.FroResult

【问题讨论】:

    标签: c# multithreading task-parallel-library .net-4.5


    【解决方案1】:

    使用FromResult 的最简单方法是:

    public Task<int> DoWork()
    {
        return Task.FromResult(99999);
    }
    

    但它在功能上完全等同于做:

    var tcs = new TaskCompletionSource<int>();
    tcs.SetResult(99999);
    return tcs.Task;
    

    所以它不会休眠 220 毫秒。对于“延迟”变体,最简单的方法是:

    public async Task<int> DoWork()
    {
        await Task.Delay(220);
        return 99999;
    }
    

    并且此版本的行为与您提供的示例非常接近。

    【讨论】:

    • 其实和我的例子不一样。 Myne 由于睡眠而在某处阻塞了线程,而您的线程自任务以来就没有。延迟使用没有阻塞的计时器
    • @RoyiNamir 确实如此,它是异步等待,而不是阻塞等待,但是由于您现在正在使用 async&await,因此一般的规则是您不应该同步等待。除非你想花时间解决死锁:)
    • @PatrykĆwiek 是的,但这并不意味着你应该说它的行为完全相同
    • @svick 对,你在技术上是正确的(最好的正确)。我做了一个小的编辑来反映这一点。 :)
    【解决方案2】:

    在您的代码中,您仅在同步等待结束后才返回Task,因此您的代码相当于:

    Task<int> DoWork()
    {
        Thread.Sleep(220);
        return Task.FromResult(9999999);
    }
    

    但如果你立即返回Task 然后阻塞了其他线程:

    Task<int> DoWork()
    {
        var source = new TaskCompletionSource<int>();
        Task.Run(() =>
        {
            Thread.Sleep(220);
            source.SetResult(9999999);
        });
        return source.Task;
    }
    

    (注意:我并不是说你应该在实际代码中这样做。)

    Task.FromResult() 无法模拟此代码,因为这总是会创建一个已经完成的Task

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-03
      • 1970-01-01
      • 2019-01-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多