在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;
}
答案 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)
并且没有中断条件,那么它将永远不会退出。