6

異步拉姆達我有一個類接收器與ActionBlock:等待在ActionBlock

public class Receiver<T> : IReceiver<T> 
{ 

    private ActionBlock<T> _receiver; 

    public Task<bool> Send(T item) 
    { 
    if(_receiver!=null) 
     return _receiver.SendAsync(item); 

    //Do some other stuff her 
    } 

    public void Register (Func<T, Task> receiver) 
    { 
    _receiver = new ActionBlock<T> (receiver); 
    } 

    //... 
} 

記數器 - 行動的ActionBlock是一個異步方法用的await-聲明:

private static async Task Writer(int num) 
{ 
    Console.WriteLine("start " + num); 
    await Task.Delay(500); 
    Console.WriteLine("end " + num); 
} 

現在我想要做的是等待同步(如果條件設置),直到動作方法完成以獲得獨佔行爲:

var receiver = new Receiver<int>(); 
receiver.Register((Func<int, Task) Writer); 
receiver.Send(5).Wait(); //does not wait the action-await here! 

問題是當「等待Task.Delay(500);」語句被執行,「receiver.Post(5).Wait();」不再等待。

我嘗試了幾種變體(TaskCompletionSource,ContinueWith,...),但它不起作用。

有沒有人有一個想法如何解決這個問題?

+0

Couldn」你可以通過改變'_receiver'到'TransformBlock'來改變你的代碼,並把下面的動作放到一個新的'ActionBlock'中,鏈接到'_receiver'? – svick

+0

你能給我一個小代碼的例子嗎?我不明白重構應該如何通過「排他行爲」問題來解決。 – obi111

回答

3

ActionBlock默認情況下會強制執行排他行爲(一次只處理一個項目)。如果你的意思是「獨佔行爲」別的東西,你可以用TaskCompletionSource通知您發送者的動作完成時:

... use ActionBlock<Tuple<int, TaskCompletionSource<object>>> and Receiver<Tuple<int, TaskCompletionSource<object>>> 
var receiver = new Receiver<Tuple<int, TaskCompletionSource<object>>>(); 
receiver.Register((Func<Tuple<int, TaskCompletionSource<object>>, Task) Writer); 
var tcs = new TaskCompletionSource<object>(); 
receiver.Send(Tuple.Create(5, tcs)); 
tcs.Task.Wait(); // if you must 

private static async Task Writer(int num, TaskCompletionSource<object> tcs) 
{ 
    Console.WriteLine("start " + num); 
    await Task.Delay(500); 
    Console.WriteLine("end " + num); 
    tcs.SetResult(null); 
} 

或者,你可以使用AsyncLockincluded in my AsyncEx library):

private static AsyncLock mutex = new AsyncLock(); 

private static async Task Writer(int num) 
{ 
    using (await mutex.LockAsync()) 
    { 
    Console.WriteLine("start " + num); 
    await Task.Delay(500); 
    Console.WriteLine("end " + num); 
    } 
} 
+0

是的你是對的,ActionBlock強制執行獨佔行爲,但如果註冊的行爲是異步的,它不再是「真正的獨佔」。是的你的解決方案應該工作,但我不想添加一個TaskCompletionSource參數,因爲該動作是專用邏輯的入口 - 所以如果用戶不調用tcs.SetResult它不會工作了... – obi111

+0

在那情況下,你可以使用'AsyncLock'。查看代碼示例的更新答案。您不再知道某個項目何時完成處理,但每個項目將一次處理一個項目(包括「異步」處理)。 –

+0

好的,謝謝,我認爲這正是我需要的 - 我會嘗試一下! – obi111