Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 了解异步/等待以管理多个客户端_C#_Multithreading_Asynchronous_Async Await - Fatal编程技术网

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