2013-06-27 21 views
1

我有這個簡單的代碼異步啓動一個方法。它使用TCS包裝與任務的代碼。將TaskCompletionSource轉換爲Task.FromResult <TResult>?

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<TResult>

這是poorly documented,所以我想知道,如何將上面的代碼轉換爲使用Task.FroResult代替?

回答

2

使用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; 
} 

並且此版本的行爲足夠接近您提供的示例。

+1

其實它不像我的例子。由於睡眠,Myne在某處有一個被阻塞的線程,而你的任務並沒有完成。延遲使用不阻塞的計時器 –

+1

@RoyiNamir足夠正確,它是異步等待,不會阻塞等待,但由於您現在正在使用異步和等待,因此tumb的一般規則是您不應該等待同步。除非你想花時間解決死鎖:) –

+1

@PatrykĆwiek是的,但這並不意味着你應該說這是行爲*完全相同。 – svick

1

在代碼中,你返回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; 
} 

(注:我不是說你應該在真正的代碼做到這一點。)

此代碼不能被012模擬,因爲它總是會創建一個已經完成的Task