簡體   English   中英

等待來自永不結束的任務的事件的異步

[英]Wait async for a event from a never ending Task

目前我正構建一個需要等待傳入消息的Web服務器,但我需要異步等待這些消息。 這些消息在另一個繼續運行的Task中接收。 無盡的任務推動事件,其他任務需要等待其中一個事件被接收。

如果需要,如果需要更好地可視化問題

我已經看到了TaskCompletionSource類,但是除非客戶端斷開連接以便不能正常工作,否則任務將無法完成。 等待任務完全相同。

C#/ .net core是否有庫或構建解決方案?

謝謝 :)

.NET Core 2.1和System.Threading.Channels中有新的Channel<T> API,允許您異步使用隊列:

Channel<int> channel = Channel.CreateUnbounded<int>();
...
ChannelReader<int> c = channel.Reader;
while (await c.WaitToReadAsync())
{
    if (await c.ReadAsync(out int item))
    {
         // process item...
    }
}

有關如何使用它的介紹和更多示例,請參閱博客文章。

通道

ASP.NET Core SignalR使用Channels實現事件流 - 發布方法異步生成由另一個方法處理的事件。 在SignalR的情況下,它是一個消費者,將每個新事件推送給客戶。

在代碼中執行相同操作很容易,但請確保遵循SignalR文檔中顯示的模式 - 通道由工作程序本身創建,並且永遠不會向調用者公開。 這意味着沒有關於通道狀態的模糊性,因為只有工人可以關閉它。

另一個重要的一點是,你必須在完成后關閉頻道,即使有異常。 否則,消費者將無限期地阻止。

您還需要將CancellationToken傳遞給生產者,以便您可以在某個時刻終止它。 即使您不打算明確取消生成器,也需要一種方法來告訴它在應用程序終止時停止。

以下方法創建通道確保即使發生異常也會關閉。

ChannelReader<int> MyProducer(someparameters,CancellationToken token)
{
    var channel=Channel.CreateUnbounded<int>();
    var writer=channel.Writer;

    _ = Task.Run(async()=>{
            while(!token.IsCancellationRequested)
            {
                var i= ... //do something to produce a value
                await writer.WriteAsync(i,token);
            }
        },token)
        //IMPORTANT: Close the channel no matter what.
        .ContinueWith(t=>writer.Complete(t.Exception));                
    return channel.Reader;
}

如果生產者正常完成或者通過令牌取消了工作人員任務,則t.Exception將為null。 沒有理由使用ChannelReader.TryComplete因為一次只有一個任務是寫入編寫器。

消費者只需要該讀者消費這些事件:

async Task MyConsumer(ChannerReader<int> reader,CancellationToken token)
{
    while (await reader.WaitToReadAsync(cts.Token).ConfigureAwait(false))
    {
        while (reader.TryRead(out int item))
        {
           //Use that integer
        }
    }
}

哪個可用於:

var reader=MyProducer(...,cts.Token);
await MyConsumer(reader,cts.Token);

IAsyncEnumerable

我在這里作了一點欺騙,因為我從ChannelReader.ReadAllAsync方法復制了循環代碼,該方法返回一個允許異步循環的IAsyncEnumerable。 在.NET Core 3.0和.NET Standard 2.1中(但不僅如此),可以用以下內容替換消費者:

await foreach (var i from reader.ReadAllAsync(token))
{
     //Use that integer
}

Microsoft.Bcl.AsyncInterfaces包為以前的.NET版本添加了相同的接口

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM