C# 了解异步/等待以管理多个客户端
我被C# 了解异步/等待以管理多个客户端,c#,multithreading,asynchronous,async-await,C#,Multithreading,Asynchronous,Async Await,我被await/async弄糊涂了,因为我可能还没有弄清楚它的正确用法 我有一个简单的WPF-UI和ViewModel-method来开始监听想要连接的客户端。 当用户单击按钮开始侦听时,将执行以下方法: public void StartListening() { _tcpListener.Start(); // TcpListener IsListening = true; // bool Task.Factory.StartNew(DoStartListeningA
await/async
弄糊涂了,因为我可能还没有弄清楚它的正确用法
我有一个简单的WPF
-UI和ViewModel
-method来开始监听想要连接的客户端。
当用户单击按钮开始侦听时,将执行以下方法:
public void StartListening()
{
_tcpListener.Start(); // TcpListener
IsListening = true; // bool
Task.Factory.StartNew(DoStartListeningAsync, TaskCreationOptions.LongRunning);
}
调用的方法doStartListingAsync
定义如下
private async Task DoStartListeningAsync()
{
while (IsListening)
{
using (var newClient = await _tcpListener.AcceptTcpClientAsync() /*.WithWaitCancellation(_cts.Token)*/)
{
apiClient = new ApiClient();
if(await apiClient.InitClientAsync()) // <-- here is the problem
{
// ... apiClient is now initialized
}
// ... do more and go back to await _tcpListener.AcceptTcpClientAsync()
}
}
}
但是,有时InitClientAsync
-调用会在await\u apiWebRequest.GetRequestStreamAsync()
处卡住,然后会在/处冻结doStartListingAsync
-方法的执行,因为您在代码路径上使用了“await”关键字,所以实际上不会提供服务
多个客户端异步运行
问题是,后台线程中的代码将一个接一个地为客户机服务。更深入地查看—在获取请求流的while循环中,等待它被加载,为它提供服务,然后等待其他请求流
async/await
原则本身并不能同时为多个操作提供服务。它所做的唯一一件事是防止阻塞当前线程被其他代码重用。因此,如果使用async/await
,则允许system yo使用当前任务线程,同时等待其他异步操作完成(如\u apiWebRequest.GetRequestStreamAsync()
)
但是,由于您有一个任务,并且等待while循环的每次迭代,如果您完全同步编写代码,那么您的代码将以相同的方式工作。唯一的好处是您正在使用Task,因此当您等待异步操作完成时,.Net可以从线程池中重用它的线程
若您不想异步地为多个客户机提供服务,那个么您应该启动多个任务,或者不要等到请求得到完全服务—所以实际上从代码中删除一些等待
因此,您应该转向设计,您有一个侦听任务/线程,除了读取请求并将其放入某个队列之外,它什么也不做。还有其他任务,为请求提供服务,从队列中读取请求
如果我没听错的话,你是在幕后使用TcpListener。因此,您需要的是一个循环,在这个循环中,您接受新客户机,并开始在不同的线程/任务中为它们提供服务,而无需等待,因此直接转到接受其他客户机。但是您可以而且应该在为客户机服务的处理程序中使用async/await
看看这一点-不完全是您的情况(因为我不知道实现的所有细节),只是为了了解这个想法。您可能想阅读Eric Lippert的:“异步方法的全部要点是尽可能多地停留在当前线程上”,这可能是一个单独的问题,但是,在将请求流传递给StreamWriter之后,在使用_apitStreamWriter之前,您应该先处理请求流吗?一般来说,您应该使用Task.Run
,而不是Task.Factory.StartNew
和async await。@i3arnon:您能更详细地解释一下原因吗?@KingKerosin
public async Task<bool> InitClientAsync()
{
using (var requestStream = await _apiWebRequest.GetRequestStreamAsync())
{
_apiStreamWriter = new StreamWriter(requestStream);
}
// ... do somehing with the _apiStreamWriter
return true;
}