如何在c#异步任务

时间:2015-09-08 10:58:06

标签: c# multithreading asynchronous blocking

我正在寻找一种简单有效的异步(等待/阻止)方法,而不必在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#异步任务库。我显然没有意识到这一点,也从未使用它。你建议我用什么?

2 个答案:

答案 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;