【问题标题】:How to await an async method which isn't expected to return如何等待不希望返回的异步方法
【发布时间】:2021-10-06 18:04:27
【问题描述】:

我正在制作一个 TCP 服务器。我正在使用 async/await 来处理多线程。我用来监听传入客户端和后续消息的方法看起来有点像这样:

private static async Task Listener()
        {
            while (Online)
            {
                TcpClient socket = await tcpListener.AcceptTcpClientAsync();
                OnReceivedTcpClient(socket);
            }           
        }

如您所知,此方法预计不会很快返回。我的问题是关于我应该如何调用这个监听器方法。目前我这样做的方式是这样的:

(控制台应用程序) 在 Main 的 Program.cs 中,我调用 Server.Start()

static void Main(string[] args)
        {
            Console.Title = "Server (Prototype)";

            Server.Start(100, 26950);

            ConsoleKeyInfo input;
            do
            {
                input = Console.ReadKey();

                // check input and do stuff
                }
        }
            while (input.Key != ConsoleKey.C);  
            
        }

Server.Start 初始化一些值,然后调用一个事件,该事件又调用监听器

private static event EventHandler<EventArgs> StartEvent;
private static void OnStartEvent() => StartEvent?.Invoke(null, new EventArgs());

public static void Start(int maxClients, int port)
        {
            Stop();
            Console.WriteLine("Starting server...");
            Init(maxClients, port);
            OnStartEvent();
        }

private async void ServerOnStartEvent(object sender, EventArgs e)
        {           
            Online = true;          
            Console.WriteLine($"Server started on port {Port}");
            await Listener();
        }

如果我调用了 await Listener();在 Server.Start 内部,那么该方法将需要 async 关键字,并且它必须返回 void (我知道这不是一个理想的设计)或返回一个 Task ,这意味着我必须调用 _ = Server.Start( ) 在 program.cs 中(这也不是很好的设计)。

所以我的问题是,我的解决方案是等待异步任务方法的好方法吗?有更好的方法吗?

【问题讨论】:

  • Async/await 不适用于多线程。如果您需要另一个线程在后台运行,请创建另一个线程。这是正确的方法。
  • 啊,我知道我错误地认为多线程和异步编程是相同的。我会研究是否应该改为多线程。
  • @Sami Kuhmonen - 好点。这是一篇很棒的文章,有助于阐明何时使用 Async/Await,以及何时使用线程可能更合适:baeldung.com/cs/async-vs-multi-threading
  • 我一直在阅读这方面的内容。如果我错了,现在纠正我,但是如果调用者线程没有足够的资源,异步任务会使用线程池。这表明异步任务确实是多线程的,但仅在必要时。

标签: c# asynchronous server async-await


【解决方案1】:

我通常处理这个问题的方法是添加一个Stop-方法。因此 Start 启动任务并将其保存在字段中。 stop 方法请求任务停止(通过任何方式),并返回存储的任务。

所以调用者可以等待 stop 方法的结果,一旦任务完成,调用者可以确保所有资源都被清理等等。

一种变体是让 Start 方法返回类似 IAsyncDisposable 的内容,这可以允许 using 语句在超出范围时自动停止并等待清理。

例子:

public class MyClass
    volatile bool stopRequested; // or use CancellationTokenSource
    Task task;
    public void Start() => task = Task.Run(DoWork); // Should probably make this "longRunning"
    public void DoWork(){
        while(!stopRequested){
            // Do something that take a limited amount of time.
        }
        // Do cleanup
    }
    public Task Stop(){
        stopRequested = true;
        return task;
    }

【讨论】:

  • 感谢@JonasH 的回复!能否提供一个代码示例?
猜你喜欢
  • 2013-07-24
  • 1970-01-01
  • 2013-02-14
  • 2017-09-24
  • 2020-03-13
  • 1970-01-01
  • 1970-01-01
  • 2021-12-01
  • 1970-01-01
相关资源
最近更新 更多