2017-09-17 73 views
0

我的意思是說,我們有一個異步方法Task<string> CalculateSha256(string s)。是否有可能,線程#1和線程#2的調用連續執行被認爲是同時執行的,沒有線程#1和#2知道對方的任何事情嗎?例如,我有一個控制器,是否有可能在不同的線程上等待任務完成?

public async Task<string> Get(string value) 
{ 
    return await CalculateSha256(value); 
} 

,我想兩個不同的請求訪問的代碼塊這是負責計算(CalculateSha256)連續。

+0

這是一個不同的問題,因爲這兩個線程不應該等待**相同的**任務,但是,爲了繼續,應該等待另一個線程的結束。 – nicks

+0

你能展示你想要達到的目標嗎?也許任務的'ContinueWith()'可能是一個答案?或者'TaskCompletionSource'類? – orhtej2

回答

4

您需要同步對CalculateSha256方法的訪問,以便一次只有一個線程執行它。
由於lock聲明does not play nicely with async您可以使用SemaphoreSlim類。

只要將其添加爲一個靜態字段到控制器:

private static readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1); 

而在你的動作使用WaitAsync方法(不要忘了釋放它,當你完成,使用finally塊):

public async Task<string> Get(string value) 
{ 
    await _semaphoreSlim.WaitAsync(); 
    try 
    { 
     return await CalculateSha256(value); 
    } 
    finally 
    { 
     _semaphoreSlim.Release(); 
    } 
} 

如果您發現這種方法非常有用,你不喜歡reapeat在try finally塊,你可以創建一個基控制器類與受保護的通用助手:

protected async Task<T> GetConsecutively(Func<Task<T>> taskFactory) 
{ 
    await _semaphoreSlim.WaitAsync(); 
    try 
    { 
     return await taskFactory(); 
    } 
    finally 
    { 
     _semaphoreSlim.Release(); 
    } 
} 

並修改Get方法lambda表達式傳遞給它:

public async Task<string> Get(string value) 
{ 
    return await GetConsecutively(() => CalculateSha256(value)); 
} 

或者選擇使用斯蒂芬·克利裏的AsyncLock代替SemaphoreSlim支持高層次的API接近lock聲明:

private static readonly AsyncLock _asyncLock = new AsyncLock(); 

public async Task<string> Get(string value) 
{ 
    //Notice the use of using block 
    //instead of try and finally 
    using(await _asyncLock.LockAsync()) 
    { 
     return await CalculateSha256(value); 
    } 
} 
+0

如果您概括您的答案,以便它可以爲任何'任務'工作,您可以在將來得到更多upvotes –

+0

@ L.B感謝您的提示,請參閱我的編輯:) – YuvShap