一个任务输入到另一个任务的输出

时间:2019-11-18 17:07:09

标签: c# multithreading winforms

在Winforms中,我具有以下内容:ProcessClientAsync将元素添加到ConcurrentDictionary。如何确保forloop在Task.Run()之后运行。我试图删除ConfigureAwait,但它冻结了UI。

public async Task Listen(int port)
{
    try
  {
    IPAddress serverAddress = IPAddress.Parse("127.0.0.1"); // localhost

    _listener = new TcpListener(serverAddress, port);
    _listener.Start();

    while (true)
    {  
      TcpClient tcpClient = await _listener.AcceptTcpClientAsync();
      await Task.Run(() => ProcessTcpClientAsync(tcpClient).ConfigureAwait(false));
      _statusText.StatusUpdate = "number of users are " + _mapClient.GetUsers().Count;

    }
  }
  catch (SocketException ex)
  {
    string message = string.Format("Error listening on port {0}. Make sure IIS or another application is not running and consuming your port.", port);
    throw new Exception(message, ex);
  }
}

private async Task<string> ProcessTcpClientAsync(TcpClient tcpClient)
{
  string key = string.Empty;
  WebSocket webSocket = null;

  try
  {
    if (_isDisposed)
      return string.Empty;

    // this worker thread stays alive until either of the following happens:
    // Client sends a close conection request OR
    // An unhandled exception is thrown OR
    // The server is disposed

    // get a secure or insecure stream
    NetworkStream stream = tcpClient.GetStream();
    WebSocketHttpContext context = await _webSocketServerFactory.ReadHttpHeaderFromStreamAsync(stream);

    if (context.IsWebSocketRequest)
    {
      key = GetKeyFromContext(context);

      // _statusText.StatusUpdate = "Connection from origin.";
      webSocket = await _webSocketServerFactory.AcceptWebSocketAsync(context);

      //_statusText.StatusUpdate = "Connection accepted.";
      await RespondToWebSocketRequestAsync(tcpClient, key, webSocket);
    }
    else
    {
      //_statusText.StatusUpdate = "Http header contains no web socket upgrade request. Ignoring...";
    }
  }

  catch (Exception ex)
  {

  }
  finally
  {
    try
    {
      await webSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "Closed in server by the client", CancellationToken.None);

      tcpClient.Client.Close();
      tcpClient.Close();
    }
    catch (Exception ex)
    {
    }
  }

  return key;
}

4 个答案:

答案 0 :(得分:1)

您可以等待 Task.Run ,但请确保使父方法 async

await Task.Run(() => ProcessClientAsync(client).ConfigureAwait(false));

这将等待异步任务完成,然后执行其余代码。我建议学习更多有关异步/等待的知识。

答案 1 :(得分:1)

要阻止ProcessClientAsync调用,您可以执行以下操作:

Task.Run(() => ProcessClientAsync(client)).Wait();

如果要访问ProcessClientAsync的结果:

Task<TResult> task = null;
Task.Run(() => task = ProcessClientAsync(client)).Wait();

// task.Result contains the result

即使这行得通,也建议您等待任务,而不要等待而阻塞。

答案 2 :(得分:1)

测验,下面的变量x是什么类型?

var x = Task.Run(() => Task.Delay(1000).ConfigureAwait(false));

类型不是Task。是Task<ConfiguredTaskAwaitable>。内部ConfigureAwait(false)调用不仅毫无意义,而且还创建了一个 意外的情况,现在必须等待两次返回值:

await await x;

不要这样做。如果由于某种原因必须使用ConfigureAwait(false),则应该立即await来获得结果。不要绕过ConfiguredTaskAwaitable结构。我的建议是在您的代码中搜索该反模式的更多实例,并消除它们。

答案 3 :(得分:0)

如果您不想将父方法标记为异步,则可以使用以下方法:

Task.Wait(Task.Run(() => ProcessClientAsync(client)));

此方法具有多个重载,这些重载还允许取消和超时的可配置性:
https://docs.microsoft.com/en-us/dotnet/api/system.threading.tasks.task.wait?view=netframework-4.8

此外,如果您的代码实际上说while (true)并且没有中断条件,那么它将永远不会退出。