如何等待不期望 return 的异步方法
How to await an async method which isn't expected to return
我正在制作一个 TCP 服务器。我正在使用 async/await 来处理多线程。我用于侦听传入客户端的方法以及后续消息看起来有点像这样:
private static async Task Listener()
{
while (Online)
{
TcpClient socket = await tcpListener.AcceptTcpClientAsync();
OnReceivedTcpClient(socket);
}
}
如您所知,此方法预计不会很快 return。我的问题是关于我应该如何调用这个侦听器方法。目前我这样做的方式是这样的:
(控制台应用程序)
在 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 关键字,并且它必须 return void (我知道这不是一个理想的设计)或 return 一个任务,这意味着我必须在 program.cs 中调用 _ = Server.Start() (这也不是很好的设计)。
所以我的问题是,我的解决方案是等待异步任务方法的好方法吗?还有更好的方法吗?
我通常的处理方式是同时添加一个Stop
-method。因此 Start 启动任务并将其保存在一个字段中。 stop 方法请求任务停止(通过任何方式),并且 returns 存储的任务。
因此调用者可以等待 stop 方法的结果,一旦任务完成,调用者可以确定所有资源都已清理等。
一个变体是让 Start 方法 return 类似于 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;
}
我正在制作一个 TCP 服务器。我正在使用 async/await 来处理多线程。我用于侦听传入客户端的方法以及后续消息看起来有点像这样:
private static async Task Listener()
{
while (Online)
{
TcpClient socket = await tcpListener.AcceptTcpClientAsync();
OnReceivedTcpClient(socket);
}
}
如您所知,此方法预计不会很快 return。我的问题是关于我应该如何调用这个侦听器方法。目前我这样做的方式是这样的:
(控制台应用程序) 在 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 关键字,并且它必须 return void (我知道这不是一个理想的设计)或 return 一个任务,这意味着我必须在 program.cs 中调用 _ = Server.Start() (这也不是很好的设计)。
所以我的问题是,我的解决方案是等待异步任务方法的好方法吗?还有更好的方法吗?
我通常的处理方式是同时添加一个Stop
-method。因此 Start 启动任务并将其保存在一个字段中。 stop 方法请求任务停止(通过任何方式),并且 returns 存储的任务。
因此调用者可以等待 stop 方法的结果,一旦任务完成,调用者可以确定所有资源都已清理等。
一个变体是让 Start 方法 return 类似于 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;
}