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

C# 异步等待另一个请求而不阻塞,c#,.net,asynchronous,async-await,task,C#,.net,Asynchronous,Async Await,Task,我有一个websocket应用程序,它是OWIN中间件。当一个请求传入时,websocket处理程序的一个新实例将启动,然后在如下循环中等待icoming消息: var buffer = new byte[1024*64]; Tuple<ArraySegment<byte>, WebSocketMessageType> received; do { received = await _webSocket.ReceiveMessage(buffer, _cancel

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

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);
我一直在等待答案:

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消息

提前感谢您的每一个提示


卢卡斯

首先,我建议使用信号器,因为他们会为你处理很多困难的事情。但是如果你想自己做,请继续阅读

另外,我假设“do work”和“answer”消息可以以任何顺序到达同一个web套接字,并且您正在使用
\u concurrentAnswerDict
来协调来自
DoSomething
的传出“问题”消息与传入的“回答”消息

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

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

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);

我觉得这很奇怪。我建议使用
TaskCompletionSource
的键字典,而不是
Answer
。然后,
QueueAnswer
将调用
TaskCompletionSource.SetResult
,此代码将只等待
TaskCompletionSource.Task
(如果需要超时,则与
Task.Delay

您应该使用信号r并在客户端接收响应。 或者最好在客户端发送请求并在客户端接收


当您向服务器发送请求并等待响应时,使用wait将被阻止。

不清楚最后一段代码是从哪里来的。那是什么东西吗?如果您可以提供一个简单的任务,而不仅仅是零碎的任务,那么它将非常有用。
等待任务。Run(…)
通常是某种形式误解的警告信号。您正在一个完全可用的线程上运行代码。您将把工作推到新任务中,然后放弃正在使用的线程,直到新的
任务
完成。
如何使DoSomething在完成之前等待另一条websocket消息?
它等待的消息是否总是下一条消息?如果是这样,
DoSomething
可以直接调用
\u webSocket.ReceiveMessage
@jonsket是的,这是我试图解决
DoSomething
中的问题。我将在几分钟内提供一个mcve,这需要一些时间,因为有很多OWIN和websocket的东西正在发生…@Damien_The_unsiever,但不会在原始线程块中运行循环来读取新消息?省略等待使其工作。谢谢你的详细回答!:)
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);
while (!_concurrentAnswerDict.TryGetValue(someKey, out tmpAnswer)) {
  await Task.Delay(150, answerCancel.Token);
}