Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 对异步方法的队列调用_C#_Queue_Async Await - Fatal编程技术网

C# 对异步方法的队列调用

C# 对异步方法的队列调用,c#,queue,async-await,C#,Queue,Async Await,我有一个名为Refresh的异步操作。如果在第一次调用完成之前进行了第二次刷新调用,我需要对其进行排队。这就是我所拥有的: public async Task Refresh(RefreshArgs refreshArgs) { await EnqueueRefreshTask(refreshArgs); } private Queue<RefreshArgs> refreshQueue = new Queue<RefreshArgs>(); priv

我有一个名为Refresh的异步操作。如果在第一次调用完成之前进行了第二次刷新调用,我需要对其进行排队。这就是我所拥有的:

public async Task Refresh(RefreshArgs refreshArgs)
{
    await EnqueueRefreshTask(refreshArgs);
}

private Queue<RefreshArgs> refreshQueue =
    new Queue<RefreshArgs>();

private async Task EnqueueRefreshTask(RefreshArgs refreshArgs)
{
    refreshQueue.Enqueue(refreshArgs);

    await ProcessRefreshQueue();
}

private Task currentRefreshTask = null;

private async Task ProcessRefreshQueue()
{
    if ((currentRefreshTask == null) || (currentRefreshTask.IsCompleted))
    {
        if (refreshQueue.Count > 0)
        {
            var refreshArgs = refreshQueue.Dequeue();

            currentRefreshTask = DoRefresh(refreshArgs);
            await currentRefreshTask;

            await ProcessRefreshQueue();
        }           
    }
}

private async Task DoRefresh(RefreshArgs refreshArgs)
{
    // Lots of code here, including calls to a server that are executed with await.
    // Code outside my control may make another Refresh(args) call while this one is still processing.
    // I need this one to finish before processing the next.
}

ActionBlock将对第二次刷新进行排队,但在刷新完成之前,等待将结束。我需要他们在DoRefresh完成工作后返回。

你可以看看这些帖子,它们讨论异步协调(信号量、重置事件)和使用任务的排除:

[编辑:添加第6部分]


    • 我认为最简单的方法是使用
      异步锁。你可以买一本,也可以阅读

      使用
      AsyncLock
      时,实现
      Refresh()
      非常简单:

      public async Task Refresh(RefreshArgs refreshArgs)
      {
          using (await m_lock.LockAsync())
          {
              // do your async work here
          }
      }
      
      这将确保
      Refresh()

      您可以使用TPL数据流中的
      ActionBlock
      来执行同样的操作,但是您还需要使用
      TaskCompletionSource
      ,它比
      AsyncLock
      版本复杂得多。

      这非常简单:) 只有你需要使用“开关盒”!! 现在,让我们来演示如何使用小样本代码。 示例场景:我们想下载2个pic,一个接一个作为队列

      名称空间测试 {

      }

      在VS 2015 windows窗体中使用C#4.6进行测试。 我自己的创新方法:)
      我希望你能用一个
      ActionBlock
      来代替这一切,这是我想到的。在处理异步数据序列时,TPL数据流(ActionBlock是其中的一部分)是一种很好的方法。我认为这更多地属于codereview站点。请注意,
      Queue
      不是线程安全的;您应该改为使用
      BlockingCollection
      。还有ConcurrentQueue-您在最有用的原语之前停止:
      AsyncLock
      。Stephen Toub在一篇文章中谈到了这一点。
      await Refresh(RefreshArgs.Something);
      // other code goes here. It expects the first refresh to be finished.
      await Refresh(RefreshArgs.SomethingElse);
      // other code goes here. It expects the second refresh to be finished.
      
      public async Task Refresh(RefreshArgs refreshArgs)
      {
          using (await m_lock.LockAsync())
          {
              // do your async work here
          }
      }
      
      public partial class SampleOfQueue : Form
      {
      
          public SampleOfQueue() { InitializeComponent(); }
          DBContext db = new DBContext();
          int Queue;
      
          private void btnStartApp_Click(object sender, EventArgs e)
          {
              Queue = 0;
              DownloadQueue();
          }
      
          private void DownloadQueue()
          {
              switch (Queue)
              {
                  case 0:
                      {
                          DownloadFile("http://images.forbes.com/media/lists/53/2009/tom-cruise.jpg", "Tom Cruise 1", "");
                          Queue += 1; break;
                      }
                  case 1:
                      {
                          DownloadFile("https://upload.wikimedia.org/wikipedia/commons/6/69/Tom_Cruise_Collateral.jpg", "Tom Cruise 2", "");
                          Queue += 1; break;
                      }
                  case 2:
                      {
                          // Other....
                          Queue += 1; break;
                      }
                  default: break;
              }
      
          }
      
          public void DownloadFile(string urlAddress, string ImageName, string ImageFarsiName)
          {
              WebClient webClient = new WebClient();
              webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
      
              Uri URL = urlAddress.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ? new Uri(urlAddress) : new Uri(urlAddress);
              webClient.DownloadFileAsync(URL, "d:\\x.jpg");
      
          }
      
          private void Completed(object sender, AsyncCompletedEventArgs e)
          {
              DownloadQueue();
              if (Queue == 3) { MessageBox.Show("finish"); }
          }
      
      }