gpt4 book ai didi

c# - 异步等待另一个请求而不阻塞

转载 作者:行者123 更新时间:2023-11-30 23:24:27 24 4
gpt4 key购买 nike

我有一个 websocket 应用程序,它是一个 OWIN 中间件。当收到请求时,将启动 websocket 处理程序的新实例,然后在循环中等待传入的消息,如下所示:

var buffer = new byte[1024*64];
Tuple<ArraySegment<byte>, WebSocketMessageType> received;
do
{
received = await _webSocket.ReceiveMessage(buffer, _cancellationToken.Token);
if (received.Item1.Count > 0 && someConditionForCallingDoSomething)
{
await DoSomething(received.Item1);
}
else if(isAnswer)
{
QueueAnswer(received.Item1);
}
} while (received.Item2 != WebSocketMessageType.Close);

_webSocket.ReceiveMessage 返回的任务将在数据可用时完成。

DoSomething 处理它的数据,然后通过 websocket 连接发送一些东西。然后它应该等待通过 websocket 连接的消息。处理此消息后,它应该做一些工作并返回(任务)。也许这个小图更容易解释它:

_______________
| DoSomething |
|-------------|
| Work ---------> Send WS message
| |
| ?? |
| |
| More Work <------- Receive WS message
| | |
| V |
| return; |
|_____________|

Do some work with the data
|
V
Send a message
|
V
Wait for an answer
|
V
Process answer
|
V
finish

我尝试等待答案的内容:

var answerCancel = new CancellationTokenSource();
answerCancel.CancelAfter(30 * 1000);

var answer = await Task.Run(async () =>
{
string tmpAnswer = null;

while (!_concurrentAnswerDict.TryGetValue(someKey, out tmpAnswer)) {
await Task.Delay(150, answerCancel.Token);
}

return tmpAnswer;
}, answerCancel.Token);

但这似乎会阻塞,直到任务被取消。当我调试程序时,我在 30 秒后看到 QueueAnswer 的调用。我以为 Task.Run 会在新线程中运行该函数,但似乎并没有。从 Task.Run 阻塞的角度来看,我认为它不起作用是合乎逻辑的,因为我等待 DoSomething 的执行,因此接收新消息将被阻塞也是。

我的问题是:如何实现这样的行为?如何让 DoSomething 在完成之前等待另一个 websocket 消息?

预先感谢您的每一个提示

卢卡斯

最佳答案

首先,我建议使用 SignalR,因为它们可以为您处理很多这样的难题。但如果您想自己做,请继续阅读...

此外,我假设“做工作”和“回答”消息可以以任何顺序到达同一个网络套接字,并且您正在使用 _concurrentAnswerDict协调来自 DoSomething 的传出“问题”消息带有传入的“回答”消息。

在那种情况下,您将需要一个独立于DoSomething 的“websocket 阅读器”任务。 ;你不能让你的读者await DoSomething因为那会阻止阅读答案。我认为这是您遇到的主要问题。

这是可以接受的极少数情况之一 await一个任务。假设 DoSomething将捕获它自己的异常并处理日志记录等等,然后我们可以将它视为一个独立的“主”并忽略它返回的任务:

var buffer = new byte[1024*64];
Tuple<ArraySegment<byte>, WebSocketMessageType> received;
do
{
received = await _webSocket.ReceiveMessage(buffer, _cancellationToken.Token);
if (received.Item1.Count > 0 && someConditionForCallingDoSomething)
{
var _ = DoSomething(received.Item1);
}
else if(isAnswer)
{
QueueAnswer(received.Item1);
}
} while (received.Item2 != WebSocketMessageType.Close);

这应该允许 QueueAnswerDoSomething 时运行尚未完成。

I thought, Task.Run will run the function in a new thread, but it seems like it does not. From the view that Task.Run is blocking, it seems logical to me that it does not work, because I await the execution of DoSomething, therefore receiving new messages will be blocked too.

Task.Run 正在在另一个线程中运行。但是DoSomething正在(异步)等待它完成,读取循环正在(异步)等待DoSomething。在阅读下一条消息之前完成。

其他说明:

while (!_concurrentAnswerDict.TryGetValue(someKey, out tmpAnswer)) {
await Task.Delay(150, answerCancel.Token);
}

这对我来说似乎很奇怪。我建议使用键字典来 TaskCompletionSource<Answer>而不是 Answer .然后,QueueAnswer会调用TaskCompletionSource<Answer>.SetResult , 而这段代码只会等待 TaskCompletionSource<Answer>.Task (以及 Task.Delay 如果需要超时)。

关于c# - 异步等待另一个请求而不阻塞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37809664/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com