如何在新线程上运行任务并立即返回给调用者?

Mar*_*rin 9 .net c# multithreading asynchronous async-await

在过去的几个月里,我一直在阅读C#中的async-await以及如何正确使用它.

出于实验练习的目的,我正在构建一个小型Tcp服务器,该服务器应该为连接它的客户端提供服务.该程序是一个控制台应用程序.

我使用while循环来等待连接,如下所示:

while (!_isStopRequested)
{
       TcpClient client = await _tcpListener.AcceptTcpClientAsync();

       await Task.Factory.StartNew(() => ProcessClientAsync(client), TaskCreationOptions.LongRunning);
} 
Run Code Online (Sandbox Code Playgroud)

所以,到目前为止,我所做的ProcessClientAsync方法被标记为async void,我只是将其称为ProcessClientAsync(客户端),并且调用将立即返回给调用者.但是我在网上看到,除非是为了一个活动,否则使用它是一个糟糕的决定.所以我将定义更改为异步任务.

好的,但没有等待,我在Visual Studio中收到警告"因为没有等待此调用,当前方法在调用完成之前继续运行".

一旦我使用了等待ProcessClientAsync(客户端),代码就不起作用了.我只能连接一个客户端,然后调用者"等待"ProcessClientAsync返回.但是,该方法具有无限循环并且不会返回,但我需要while循环来继续处理下一个客户端.

谷歌搜索我来到这个线程: 如何在没有等待的情况下安全地调用C#中的异步方法

我想问题几乎是一样的,除了当我使用await ProcessClientAsync时,我希望它立即返回到调用者,它不会这样做,我知道因为运行第二个客户端,而第一个客户端仍在运行,第二个客户端没有连接.

所以我这样做了:

await Task.Factory.StartNew(() => ProcessClientAsync(client), TaskCreationOptions.LongRunning);
Run Code Online (Sandbox Code Playgroud)

但是由于ProcessClientAsync必须返回一个Task,我不确定这是否可以.

那将是一个问题.

另一个是:我怎么能调用一个永远运行的异步Task方法,让调用立即返回调用者,这样while循环可以继续,tcp监听器可以继续接受下一个客户端?

谢谢.

对不起,如果是重复,或不清楚我在问什么.

Ste*_*ary 12

出于实验练习的目的,我正在构建一个小型Tcp服务器,该服务器应该为连接它的客户端提供服务.该程序是一个控制台应用程序.

嗯,我建议的第一件事是尝试更简单的练习.说真的,异步TCP服务器是您可以选择的最复杂的应用程序之一.绝大多数开发人员使用async的应用程序都比两个数量级更简单.

而不是尝试编写将从URL下载文件的UI应用程序.这是一个更现实的学习起点async.

但是由于ProcessClientAsync必须返回一个Task,我不确定这是否可以.

我推荐使用Task.Run而不是Task.Factory.StartNew.Task.Run意识到async方法,而StartNew不是.

但是,假设开始一个线程是首先正确的操作.大多数TCP/IP服务器应用程序不受CPU限制,所以我在这里质疑多线程的使用.完全可能有一个完全异步的TCP/IP服务器,它只使用线程池进行async方法延续.

另一个是:我怎么能调用一个永远运行的异步Task方法,让调用立即返回调用者,这样while循环可以继续,tcp监听器可以继续接受下一个客户端?

你只是没有awaitTask它的回报:

Task.Run(() => ProcessClientAsync(client));
Run Code Online (Sandbox Code Playgroud)

但是,编译器会在这里抱怨,因为这段代码几乎肯定是错误的.如果忽略返回的任务,那么您将忽略该代码中的任何异常.

TCP/IP服务器应用程序中的一种常见模式是为每个连接的客户端维护一小部分状态.这是放置套接字对象本身和代表该套接字连接处理的任务的自然场所:

var clientState = new ClientState(client);
clientState.Task = Task.Run(() => ProcessClientAsync(client));
Run Code Online (Sandbox Code Playgroud)

然后将这些客户端状态存储在列表/字典中.你究竟如何做到这一点当然取决于你.