订单处理任务

时间:2016-10-24 23:43:49

标签: c# task

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

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

目前,我的事件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)的竞争条件btw行。例如,事件被触发4次:

  1. (1)为真,(2)在任务中排队等待运行
  2. (1)为真,(2)在任务中排队等待运行
  3. (1)为真,(2)在任务中排队等待运行
  4. (1)为真,(2)在任务中排队等待运行
  5. 现在,任务队列有4个要运行的任务,但这些任务不会以相同的顺序执行。它们可以以任何顺序执行,即3-> 2-> 4-> 1但我需要它们以1-> 2-> 3-> 4执行而不阻塞UI线程。

    如何在不阻止UI线程的情况下实现此目的?

2 个答案:

答案 0 :(得分:0)

我会考虑使用Microsoft的Reactive Framework(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,您可以随时使用它来停止处理 - 它会有效地从事件中分离出来。

答案 1 :(得分:-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文章中提供。

该解决方案运行良好,该任务不会在与实例化任务的方法相同的线程上执行,从而提高性能。