【问题标题】:Process Tasks in Order按顺序处理任务
【发布时间】:2016-10-24 23:43:48
【问题描述】:

我每次都会发生一些事件通知,例如将文件添加到文件夹中(这不是我的情况,只是一个类比来解释)。

文件夹中可以添加任意数量的文件,我们不知道会有多少。

目前,每次添加文件时都会触发我的事件 myEvent_Handler

private void myEvent_Handler(object sender, SomeEvent e)
{
  // I dont know how many times this event will fire
  if (something == true) (1)
  {
    var t = Task.Run(() =>
    {
      DoSomething(e);  (2)
    });
  }
}

上述事件处理程序中的问题是标有 (1) 和 (2) 的竞态条件。例如,该事件被触发 4 次:

  1. (1) 为真,(2) 在任务中排队运行
  2. (1) 为真,(2) 在任务中排队运行
  3. (1) 为真,(2) 在任务中排队运行
  4. (1) 为真,(2) 在任务中排队运行

现在,任务队列有 4 个任务要运行,但这些任务的执行顺序不同。它们可以按任何顺序执行,即 3->2->4->1 但我需要它们按 1->2->3->4 执行而不阻塞 UI 线程。

如何在不阻塞 UI 线程的情况下实现这一点?

【问题讨论】:

  • 听起来像是任务队列
  • 听起来您可以将长时间运行的任务与队列一起使用。请参阅此解决方案:stackoverflow.com/questions/2293976/…
  • 谢谢,但我最大的问题是,到目前为止,我所读到的所有内容都要求客户知道何时标记加载队列的结束,而我无法解决如何做到这一点为我的场景工作。
  • 使用ContinueWith方法链接多个任务。

标签: c# task


【解决方案1】:

我会考虑为此使用 Microsoft 的反应式框架 (NuGet "System.Reactive")。很理想。

Observable
    .FromEventPattern<EventHandler, EventArgs>(
        h => myEvent.Handler += h, h => myEvent.Handler -= h)
    .ObserveOn(Scheduler.Default)
    .Subscribe(ep => DoSomething(ep.EventArgs));

它将自动编组到后台线程 (Scheduler.Default),并保证每个订阅调用都等到前一个调用完成后再继续。

这将完全取代myEvent_Handler 方法。

.Subscribe(...) 调用返回 IDispose,您可以随时使用它来停止处理 - 它有效地与事件分离。

【讨论】:

    【解决方案2】:

    我想通了并重写了上面的代码来做到这一点:

    private void myEvent_Handler(object sender, SomeEvent e)
    {
      // I dont know how many times this event will fire
      Task t = new Task(() =>
      {
        if (something == true) 
        {
            DoSomething(e);  
        }
      });
      t.RunSynchronously();
    }
    

    效果很好,不会阻塞我的 UI 线程。

    更新:虽然我发现这对我很有用(它修复了我的竞争条件并且我的 UI 线程没有被阻塞),但经过进一步调查,我发现调用此代码的方法没有在 UI 线程上执行(这解释了为什么这段代码没有阻塞我的 UI 线程)但是检查 ManagedThreadId,我发现上面的任务在运行这个方法的同一个线程上运行。 结果,我根据这两个帖子更改了我的实现:

    https://msdn.microsoft.com/library/system.threading.tasks.taskscheduler.aspx

    How (and if) to write a single-consumer queue using the TPL?

    使用 LimitedConcurrencyLevelTask​​Scheduler(在上面的 MSDN 文章中提供。

    该解决方案效果很好,该任务与实例化任务的方法不在同一线程上执行,从而提高了性能。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-27
    • 2023-04-07
    • 1970-01-01
    相关资源
    最近更新 更多