如何在 C# Async Task 中异步等待某个条件
How to asynchronously wait on a certain condition in c# Async Task
我正在寻找一种简单有效的异步方式(等待/阻塞),而无需在 Async Task
方法中进行轮询。
我在下面创建了一个简单的伪代码情况:
private var queue = new ConcurrentQueue<Command>();
// Function called by program
public async Task<String> GetNameAsync(int id)
{
//Build Command
var Command = new Command(id);
//Enqueue Command to concurrent queue
queue.enqueue(command);
//Wait for command to finnish executing, posibly supply a timeout
await command.CompleteCondition
//Once command has completed or timed out return the result of the task.
return command.Response.getString();
}
//Continiously runs in its own thread
private void MainThread()
{
while(mustRun)
{
if(queue.Any())
{
//Get command from queue if there is one
var command = queue.dequeue();
//Execute command
var result = ExecuteCcommand(command);
//Set Command Done with result (so the blocking async task can continue:
//TODO:
}else{
Thread.Sleep(100);
}
}
我遗漏了我不知道的机制,但本质上我需要将某种锁与命令一起传递给主线程,主线程将在完成后通知 Async Task
, 以便任务可以继续。
我确信一定有某种类型的 c# 机制,它专门设计用于 c# 异步任务库。我显然不知道它,也从未使用过它。你会推荐我使用什么?
最简单的方法是使用 TaskCompletionSource
。例如:
public class Command
{
private readonly TaskCompletionSource<string> _tcs = new TaskCompletionSource<string>();
public Task<string> ExecuteAsync()
{
return _tcs.Task;
}
internal void ExecuteCommand()
{
if (_tcs.Task.IsCompleted) return;
try
{
// Do your work...
_tcs.SetResult(result);
}
catch (Exception ex)
{
_tcs.SetException(ex);
}
}
}
执行命令时,你只是var result = await ExecuteAsync();
。在您的工作人员中,只需执行 ExecuteCommand();
.
您似乎正在尝试实施 Publish/Subscribe 方案。 .NET 为此提供了多种 classes。
最简单的一个是来自 TPL Dataflow 的 ActionBlock class。生产者可以 post 将消息(数据)发送到由消费者 Action 在单独的 Task 上处理的 ActionBlock。默认情况下,ActionBlock 使用单个任务来处理消息,但可以更改。
在这种情况下你可以这样写:
private ActionBlock<Command> _myBlock=new ActionBlock<Command>(cmd=>ExecuteCommand(cmd));
//In the producer method
_myBlock.Post(command);
ExecuteCommand
可能是您已经实施的方法。不需要处理出队或休眠,这由 ActionBlock 本身处理。
您的代码中没有解决的一个问题是,当您想停止处理时该怎么做。理想情况下,您希望停止 posting 到队列并等待任何未完成的消息完成处理。 ActionBlock 允许您简单地调用 Complete()
并通过等待其 Completion
任务来等待它完成,例如:
_myBlock.Complete();
await _myBlock.Completion;
我正在寻找一种简单有效的异步方式(等待/阻塞),而无需在 Async Task
方法中进行轮询。
我在下面创建了一个简单的伪代码情况:
private var queue = new ConcurrentQueue<Command>();
// Function called by program
public async Task<String> GetNameAsync(int id)
{
//Build Command
var Command = new Command(id);
//Enqueue Command to concurrent queue
queue.enqueue(command);
//Wait for command to finnish executing, posibly supply a timeout
await command.CompleteCondition
//Once command has completed or timed out return the result of the task.
return command.Response.getString();
}
//Continiously runs in its own thread
private void MainThread()
{
while(mustRun)
{
if(queue.Any())
{
//Get command from queue if there is one
var command = queue.dequeue();
//Execute command
var result = ExecuteCcommand(command);
//Set Command Done with result (so the blocking async task can continue:
//TODO:
}else{
Thread.Sleep(100);
}
}
我遗漏了我不知道的机制,但本质上我需要将某种锁与命令一起传递给主线程,主线程将在完成后通知 Async Task
, 以便任务可以继续。
我确信一定有某种类型的 c# 机制,它专门设计用于 c# 异步任务库。我显然不知道它,也从未使用过它。你会推荐我使用什么?
最简单的方法是使用 TaskCompletionSource
。例如:
public class Command
{
private readonly TaskCompletionSource<string> _tcs = new TaskCompletionSource<string>();
public Task<string> ExecuteAsync()
{
return _tcs.Task;
}
internal void ExecuteCommand()
{
if (_tcs.Task.IsCompleted) return;
try
{
// Do your work...
_tcs.SetResult(result);
}
catch (Exception ex)
{
_tcs.SetException(ex);
}
}
}
执行命令时,你只是var result = await ExecuteAsync();
。在您的工作人员中,只需执行 ExecuteCommand();
.
您似乎正在尝试实施 Publish/Subscribe 方案。 .NET 为此提供了多种 classes。
最简单的一个是来自 TPL Dataflow 的 ActionBlock class。生产者可以 post 将消息(数据)发送到由消费者 Action 在单独的 Task 上处理的 ActionBlock。默认情况下,ActionBlock 使用单个任务来处理消息,但可以更改。
在这种情况下你可以这样写:
private ActionBlock<Command> _myBlock=new ActionBlock<Command>(cmd=>ExecuteCommand(cmd));
//In the producer method
_myBlock.Post(command);
ExecuteCommand
可能是您已经实施的方法。不需要处理出队或休眠,这由 ActionBlock 本身处理。
您的代码中没有解决的一个问题是,当您想停止处理时该怎么做。理想情况下,您希望停止 posting 到队列并等待任何未完成的消息完成处理。 ActionBlock 允许您简单地调用 Complete()
并通过等待其 Completion
任务来等待它完成,例如:
_myBlock.Complete();
await _myBlock.Completion;