【问题标题】:How to run events sequentially in C# or Similar Frameworks如何在 C# 或类似框架中按顺序运行事件
【发布时间】:2014-04-15 13:02:14
【问题描述】:

如何取消/调节与另一个线程中的相同事件并行执行的事件。

例如在文本框中,每次我们输入一个字符时,如果定义了文本更改事件,就会触发该事件。但是在输入第一个字符后,事件(让我们称之为 First Event)需要很多时间(因为会有更多的字符串匹配单个字符),并且会执行一些操作,例如更改标题标签的内容。并且在输入第二个字符后,引发并行运行的新事件需要更少的时间。所以现在,在输入第二个字符后触发的第二个事件执行速度很快并返回第一个,第一个事件最后执行,因此,第一个事件的结果最终将打印在标签上,而不是第二个。

有没有更好的方法在开始第二个事件之前取消第一个事件。我想到的一件事是在全局列表变量上注册线程并在开始执行之前杀死所有未死的线程。这行得通吗??有什么更好的方法来处理这种情况。

附:我知道可以在空格或输入后启动搜索以解决此特定问题。但我想你已经注意到我的主要观点了。 :)

【问题讨论】:

  • 我会研究 Reactive Extensions 来操纵事件流以及任务并行库...
  • 由于 UI 是单线程事件总是按自己的顺序排列。
  • @FelicePollano 但不一定是事件发起的回调的结果。
  • 例如,如果用户输入“abc”,但您的客户端缓存了“abc”而不是“ab”的搜索结果,那么 UI 可能会更新为“abc”的结果,然后是“ab”的结果。不理想。

标签: c# multithreading events


【解决方案1】:

我最喜欢处理这个确切问题的库是Rx.NetTPL。这种行为可以通过使用Observable.FromAsyncObservable.FromAsync 结合可取消任务和事件观察者来轻松实现

一些代码!

var textChanged = Observable.FromEventPattern(x => textBox.TextChanged += x, x => textBox.TextChanged -= x)
                        .Select(_ => textBox.Text);
IDisposable eventHandler = textChanged.Throttle(TimeSpan.FromMilliseconds(500))
                              .Select(text => Observable.FromAsync((TaskCancelationToken cancel) => DoSearchTaskAsync(text, cancel)))
                              .Switch()
                              .Subscrible(results =>
                              {
                                  //Update the UI
                              });

请注意,无需显式键入任何内容...我这样做只是为了清楚起见,但我很可能打错了一个或两个类名...

编辑

Search 方法将是Task<TReturn> DoSearchTaskAsync(string, TaskCancellationToken) 的方法体。

魔法酱来自Observable.FromAsyncObservable.Switch

每次我们在 textBox.Text 中发生变化时,我们都会触发一个事件。这是由.Throttle 过滤的(如您所料)。聪明的一点是,当我们使用Observable.FromAsyncDoSearchTaskAsync 上创建一个新的事件源时。此时我们有一个IObservable<IObservable<TResult>>,或者另一种说法,一个事件源的事件源。切换意味着我们只想要外部事件源中最近发送的事件源的结果,并杀死(Dispose)之前事件源的订阅。

在我们订阅新的Task 时,处置以前的Observable.FromAsync 将导致TaskCancellationToken 取消,并防止其结果冒泡。

所有非常聪明的东西,我最近才发现这种令人敬畏的模式(如果可以的话,我会感谢作者)。

至于 Observable.FromEventPattern 很不幸,从 C#5 开始,没有一流的事件处理程序,因此我们传入一个用于订阅的 lambda 和一个用于取消订阅的 lambda。

【讨论】:

  • 如果不是太麻烦,能不能给我解释一下代码??我对这些东西有点陌生。在此先感谢.. 我正在寻找的是,1.在哪里绑定这个事件? 2. 我的搜索操作方法在哪里被调用?( DoSearchTaskAsync ??) 3. 它如何取消之前已经调用的事件?它需要参考这些方法吗?提前致谢
  • 我刚刚看到您的编辑...刷新后 :) 谢谢 :)
  • @sriharshaKB 我确实编辑了我的答案。这是我能做的最好的。不幸的是,您需要在 Rx.Net 中有良好的基础才能理解我所写的解释。
【解决方案2】:

.NET Task API 内置了取消的概念。有关示例和指向更多信息的链接,请参阅此页面。 http://msdn.microsoft.com/en-us/library/dd997396(v=vs.110).aspx

【讨论】:

  • 我想到了..但我刚刚提到了线程解决方案,因为两者都很相似。好吧,我不完全知道。但在某种程度上,我们正在用自己的双手处理这个问题。还有其他解决办法吗??并且必须以某种方式调用内置的取消。然后我们可以将它绑定到一个变量,如果它为假则停止执行。在这种情况下,我们可以将任务绑定到该变量。当下一个字符出现时,事件触发并且变量将被设置为 false 触发所有任务的结束。然后我们稍后再次将其设置为 true 并再次将新任务绑定到该变量。听起来像科幻?? :)
猜你喜欢
  • 2022-07-20
  • 2016-08-20
  • 1970-01-01
  • 2011-01-21
  • 1970-01-01
  • 1970-01-01
  • 2015-10-06
  • 1970-01-01
  • 2023-03-04
相关资源
最近更新 更多