我正在寻找一种简单有效的异步(等待/阻止)方法,而不必在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
完成后通知new Handler().post(new Runnable() {
@Override
public void run() {
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out)
.replace(R.id.container, finalMenuFragment)
.commit();
}
});
,所以任务可以继续。
我确信我必须使用某种类型的c#机制,它专门设计用于c#异步任务库。我显然没有意识到这一点,也从未使用它。你建议我用什么?
答案 0 :(得分:3)
最简单的方法是使用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();
。
答案 1 :(得分:1)
您似乎正在尝试实施发布/订阅方案。 .NET为此提供了各种类。
最简单的一个是来自TPL Dataflow的ActionBlock类。生产者可以在单独的任务上将消息(数据)发布到由消费者Action处理的ActionBlock。默认情况下,ActionBlock使用单个任务来处理消息,尽管可以更改。
在这种情况下,您可以编写如下内容:
private ActionBlock<Command> _myBlock=new ActionBlock<Command>(cmd=>ExecuteCommand(cmd));
//In the producer method
_myBlock.Post(command);
ExecuteCommand
可能是您已经实施的方法。无需处理出列或休眠,这由ActionBlock本身处理。
您的代码中未解决的问题是,当您要停止处理时该怎么做。理想情况下,您希望停止发布到队列并等待任何未完成的消息完成处理。 ActionBlock允许您简单地调用Complete()
并等待其Completion
任务等待它完成,例如:
_myBlock.Complete();
await _myBlock.Completion;