我现在已经挣扎了一段时间了。我有我想要异步处理的事件(它们长时间运行),但是如果从事件传递的数据满足条件(例如相同的id),我希望同步处理事件按顺序。
这是否可以通过RX轻松实现?或者我是否需要实现自己的线程同步和排队?
以下是说明我的问题的代码段:
class Program
{
static void Main(string[] args)
{
var trigger = new EventTrigger();
Observable.FromEvent<EventTrigger.OnNewDataHandler, int>(h => trigger.OnNewData += h, h => trigger.OnNewData -= h)
.Subscribe(LongRunning);
// Should process id 1 synchorously and in order, and ids 2, 3, 4 in parallel
trigger.RaiseEvent(1);
trigger.RaiseEvent(2);
trigger.RaiseEvent(1);
trigger.RaiseEvent(1);
trigger.RaiseEvent(3);
trigger.RaiseEvent(4);
Console.ReadKey();
}
private static void LongRunning(int id)
{
var random = new Random();
Thread.Sleep(random.Next(1, 10) * 1000);
Console.WriteLine(DateTime.Now + ": " + id);
}
}
public class EventTrigger
{
public event OnNewDataHandler OnNewData;
public delegate void OnNewDataHandler(int id);
public void RaiseEvent(int id)
{
var handler = OnNewData;
if (handler != null) handler(id);
}
}
答案 0 :(得分:2)
这可以通过内部使用Rx的Punchclock轻松完成。这是唯一一个班级唯一的方法:
IObservable<T> EnqueueObservableOperation(int priority, string key, IObservable<TDontCare> cancel, Func<IObservable<T>> asyncCalculationFunc);
任何具有相同key
参数的内容都将按顺序运行,但具有不同键的操作将并行运行。
作为一个粗略概括的经验法则,如果你有&#34;并行化&#34;在您的问题中,Rx通常不是答案!
我不同意:))
答案 1 :(得分:1)
Rx保证每个订户的事件按顺序非并发处理,因此您只需使用两个不同的订阅。使用一个用于仅利用Rx语义的同步处理事件。这必须指定一个TaskPoolScheduler(或类似的)来避免阻塞当前线程。然后使用第二个用于卸载到处理程序中任务池的异步处理事件。
var events = Observable.FromEvent<EventTrigger.OnNewDataHandler, int>(
h => trigger.OnNewData += h,
h => trigger.OnNewData -= h);
events.Where(id => id == 1)
.ObserveOn(TaskPoolScheduler.Default)
.Subscribe(LongRunning);
events.Where(id => id != 1)
.ObserveOn(TaskPoolScheduler.Default)
.Subscribe(LongRunningAsync);
使用处理程序:
private static void LongRunning(int id)
{
DoWork(id);
}
private static void LongRunningAsync(int id)
{
Task.Run(() => DoWork(id));
}
private static void DoWork(int id)
{
Console.WriteLine(DateTime.Now + ": started " + id);
var random = new Random();
Thread.Sleep(random.Next(1, 10) * 1000);
Console.WriteLine(DateTime.Now + ": finished " + id);
}
答案 2 :(得分:1)
如果您乐意开展工作,然后投射出结果,那么这就行了。
Observable.FromEvent<EventTrigger.OnNewDataHandler, int>(
h => trigger.OnNewData += h,
h => trigger.OnNewData -= h
)
.GroupBy(i=>i)
.Select(grp=>grp.ObserveOn(TaskPoolScheduler.Default).SelectMany(i=>LongRunningTransform(i)))
.Subscribe(result=>Console.WriteLine(result));
在这里,我们只需将LongRunning OnNext处理程序更改为投影
private static string LongRunningTransform(int id)
{
var random = new Random();
Thread.Sleep(random.Next(1, 10) * 1000);
return string.Format("{0:o} Id: {1} on thread {2}",
DateTime.Now ,
id,
Thread.CurrentThread.ManagedThreadId);
}