了解异步/等待以管理多个客户端 [英] Understanding async/await to manage multiple clients

查看:81
本文介绍了了解异步/等待以管理多个客户端的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对await/async感到困惑,因为我可能仍然无法正确理解其用法.

I'm getting confused by await/async as I may still not get the point of its correct usage.

我有一个简单的WPF -UI和ViewModel-方法来开始侦听要连接的客户端. 当用户单击按钮开始收听时,将执行以下方法:

I have a simple WPF-UI and a ViewModel-method to start listening for clients which want to connect. The following method is executed when the user clicks the button to start listening:

public void StartListening()
{
    _tcpListener.Start(); // TcpListener
    IsListening = true; // bool
    Task.Factory.StartNew(DoStartListeningAsync, TaskCreationOptions.LongRunning);
}

被调用的方法DoStartListeningAsync的定义如下

The method DoStartListeningAsync which is called is defined like

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()
        }
    }
}

ApiClient类的InitClientAsync方法的定义如下:

The ApiClient class' InitClientAsync method is defined like:

public async Task<bool> InitClientAsync()
{
    using (var requestStream = await _apiWebRequest.GetRequestStreamAsync())
    {
        _apiStreamWriter = new StreamWriter(requestStream);
    }

    // ... do somehing with the _apiStreamWriter

    return true;
}

但是,有时InitClientAsync调用将停留在await _apiWebRequest.GetRequestStreamAsync()上,然后将冻结在// <-- here is the problemDoStartListeningAsync方法的执行. 如果DoStartListeningAsync卡住了,将不会处理新的连接,这会破坏我异步处理多个客户端的整个概念.

However, sometimes the InitClientAsync-call will get stuck at await _apiWebRequest.GetRequestStreamAsync() which then will freeze the execution of the DoStartListeningAsync-method at // <-- here is the problem. In case the DoStartListeningAsync is stuck, no new connections will be handled which destroys my whole concept of handling multiple clients asynchronously.

推荐答案

由于您在代码路径中使用了"await"关键字,因此实际上不会提供服务

Since you are using "await" keyword along the code path, you won't actually serve

多个客户端异步

multiple clients asynchronously.

问题是,您在后台线程中的代码将为客户端一个一服务.进行更深入的研究-在while循环中,您正在获取请求流,等待它被加载,提供服务,然后等待其他请求流.

The thing is, your code in the background thread will serve clients one by one. Take a deeper look - in the while loop you are getting request stream, wait till it is loaded, serve it, and then wait for other request stream.

async/await原理本身并不能提供同时执行多个操作的功能.它唯一要做的是-阻止阻止当前线程被其他代码重用.因此,如果使用async/await,则允许系统使用当前的任务线程,同时它正在等待其他异步操作完成(例如_apiWebRequest.GetRequestStreamAsync()).

async/await principle doesn't itself provide ability to serve multiple actions at the time. The only thing it is doing - prevents blocking current thread from being reusable by other code. So if going with async/await, you allow system yo use your current task thread, while it is waiting to other async action to complete (like _apiWebRequest.GetRequestStreamAsync()).

但是,由于您只有一项任务,并且正在等待while循环的每次迭代-如果您完全同步编写代码,则它们将以相同的方式工作.唯一的好处就是您正在使用Task,因此.Net在等待异步操作完成时可以重用线程池中的线程.

But since you are having one task, and you are waiting on every iteration of while loop - your code will work the same way, if you wrote it completely synchronous. The only profit is that you are using Task, and so .Net can reuse it's thread from thread pool while you are waiting for async actions to complete.

如果您不想异步地为多个客户端提供服务,则应该启动多个任务,或者不要等到请求被完全满足-因此实际上要从代码中删除一些等待的对象.

If you wan't to serve multiple clients asynchronously, you should either start multiple tasks, or don't wait till request is completely served - so actually remove some awaits from your code.

因此,您应该朝着设计的方向前进,那里有一个侦听任务/线程,除了读取请求并将其放入某个队列外,什么也不做.还有其他处理请求的任务,从队列中读取请求.

So you should move towards design, there you have one listening task/thread, that does nothing exept reading requests and putting it to the some queue. And having other tasks, that serve requests, reading it from the queue.

如果我对您的理解正确,则说明您正在使用TcpListener.因此,您需要的是一个循环,在该循环中您可以接受新客户端,然后无需等待就开始在不同的线程/任务中为它们提供服务,因此直接转到接受其他客户端.但是您可以并且应该在为客户提供服务的处理程序中使用async/await.

If I understood you correctly, you are using TcpListener under the hood. So what you need, is the loop where you accept new clients, and start serving them in the different thread/task without any waiting, so going directly to accepting other clients. But you can and should use async/await inside those handlers that serve clients.

看看这个答案-不完全是您的情况(因为我不知道实现的所有细节) ,但只是为了了解这个主意.

Take a look at this answer - not completely your case (since I don't know all details of implementation), but just to get the idea.

这篇关于了解异步/等待以管理多个客户端的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆