如何在新线程上运行任务并立即返回给调用者? [英] How to run a Task on a new thread and immediately return to the caller?

查看:63
本文介绍了如何在新线程上运行任务并立即返回给调用者?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

For the last few months I have been reading about async-await in C# and how to properly use it.

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

For the purpose of a laboratory exercise, I am building a small Tcp server that should serve clients that connect to it. The program is a console application.

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

I use a while loop to wait for connections like so:

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

       await Task.Factory.StartNew(() => ProcessClientAsync(client), TaskCreationOptions.LongRunning);
} 

因此,到目前为止,我创建的 ProcessClientAsync 方法被标记为 async void,我将其称为 ProcessClientAsync(client),该调用将立即返回给调用方.但是,我在互联网上读到,除非用于活动,否则使用它是一个糟糕的决定.所以我将定义更改为 async Task.

So, until now the method ProcessClientAsync I made was marked as async void and I would just call it ProcessClientAsync(client) and the call would immediately return to the caller. However I read on the internet that it is a poor decision to use it unless it is for an event. So I changed the definition to async Task.

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

Ok, but without an await, I get a warning in Visual studio "Because this call is not awaited, the current method continues to run before the call is completed".

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

And once I used await ProcessClientAsync(client), the code doesn't work. I can connect only one client, and then the caller "waits" for ProcessClientAsync to return. However, that method has a infinite loop and will not return, but I need the while loop to continue processing the next client.

谷歌搜索我想到了这个线程:如何安全地调用异步方法没有等待的 C#

Googling I came up to this thread: How to safely call an async method in C# without await

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

I guess the questions are pretty much the same, except that when I use await ProcessClientAsync, I want it to return to the caller immediately, which it doesn't do, I know because running the second client, while the first is still running, the second client doesn't connect.

所以我这样做了:

await Task.Factory.StartNew(() => ProcessClientAsync(client), TaskCreationOptions.LongRunning);

但由于 ProcessClientAsync 必须返回一个任务,我不确定这样做是否可以?

But since ProcessClientAsync has to return a Task, I am not sure if this is Ok to do?

这是一个问题.

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

The other would be: how could I call a async Task method that will run forever, and have the call return to the caller immediately so the while loop can continue and the tcp listener can continue to accept the next client?

谢谢.

抱歉,如果是重复,或者不清楚我在问什么.

Sorry if it is a repetition, or unclear what I am asking.

推荐答案

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

For the purpose of a laboratory exercise, I am building a small Tcp server that should serve clients that connect to it. The program is a console application.

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

Well, the very first thing I'd recommend is to try a simpler exercise. Seriously, an asynchronous TCP server is one of the most complex applications you can choose. The vast majority of developers using async are working on apps two orders of magnitude simpler.

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

Instead of that, try writing a UI app that will download a file from a URL. That's a more realistic starting point for learning async.

但由于 ProcessClientAsync 必须返回一个任务,我不确定这样做是否可以?

But since ProcessClientAsync has to return a Task, I am not sure if this is Ok to do?

我建议使用 Task.Run 而不是 Task.Factory.StartNew.Task.Run 知道 async 方法,而 StartNew 不知道.

I'd recommend using Task.Run instead of Task.Factory.StartNew. Task.Run is aware of async methods, whereas StartNew is not.

然而,这首先假设启动线程是正确的操作.大多数 TCP/IP 服务器应用程序不受 CPU 限制,因此我在这里质疑多线程的使用.完全有可能拥有一个完全异步的 TCP/IP 服务器,它只将线程池用于其 async 方法延续.

However, that's assuming that kicking off a thread is the correct operation in the first place. Most TCP/IP server applications are not CPU-bound, so I question the use of multiple threads here. It's entirely possible to have a fully-asynchronous TCP/IP server that only uses the thread pool for its async method continuations.

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

The other would be: how could I call a async Task method that will run forever, and have the call return to the caller immediately so the while loop can continue and the tcp listener can continue to accept the next client?

你只是不await它返回的Task:

Task.Run(() => ProcessClientAsync(client));

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

However, the compiler will complain here, because this code is almost certainly wrong. If you ignore the returned task, then you're ignoring any exceptions from that code.

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

A common pattern in TCP/IP server apps is to maintain a small collection of state for each connected client. That's a natural place to put both the socket object itself and the task that represents the handling of that socket connection:

var clientState = new ClientState(client);
clientState.Task = Task.Run(() => ProcessClientAsync(client));

这些客户端状态然后存储在列表/字典中.具体如何操作当然取决于您.

These client states are then stored in a list/dictionary. How exactly you do this is of course up to you.

这篇关于如何在新线程上运行任务并立即返回给调用者?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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