C# 并行事件订阅服务器.net 4.5
我正在尝试创建并行事件订阅服务器。这是我第一次尝试:C# 并行事件订阅服务器.net 4.5,c#,.net,asynchronous,.net-4.5,C#,.net,Asynchronous,.net 4.5,我正在尝试创建并行事件订阅服务器。这是我第一次尝试: using System; using System.Collections.Generic; using System.Threading.Tasks; using EventStore.ClientAPI; namespace Sandbox { public class SomeEventSubscriber { private Position? _latestPosition; pr
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using EventStore.ClientAPI;
namespace Sandbox
{
public class SomeEventSubscriber
{
private Position? _latestPosition;
private readonly Dictionary<Type, Action<object>> _eventHandlerMapping;
private IEventStoreConnection _connection;
public Dictionary<Type, Action<object>> EventHandlerMapping
{
get { return _eventHandlerMapping; }
}
public SomeEventSubscriber()
{
_eventHandlerMapping = CreateEventHandlerMapping();
_latestPosition = Position.Start;
}
public void Start()
{
ConnectToEventstore();
}
private void ConnectToEventstore()
{
_connection = EventStoreConnectionWrapper.Connect();
_connection.Connected +=
(sender, args) => _connection.SubscribeToAllFrom(_latestPosition, false, EventOccured, LiveProcessingStarted, HandleSubscriptionDropped);
}
private Dictionary<Type, Action<object>> CreateEventHandlerMapping()
{
return new Dictionary<Type, Action<object>>
{
{typeof (FakeEvent1), o => Handle(o as FakeEvent1)},
{typeof (FakeEvent2), o => Handle(o as FakeEvent2)},
};
}
private async Task Handle(FakeEvent1 eventToHandle)
{
SomethingLongRunning(eventToHandle);
}
private async Task Handle(FakeEvent2 eventToHandle)
{
SomethingLongRunning(eventToHandle);
}
private async Task SomethingLongRunning(BaseFakeEvent eventToHandle)
{
Console.WriteLine("Start Handling: " + eventToHandle.GetType());
var task = Task.Delay(10000);
await task;
Console.WriteLine("Finished Handling: " + eventToHandle.GetType());
}
private void EventOccured(EventStoreCatchUpSubscription eventStoreCatchUpSubscription,
ResolvedEvent resolvedEvent)
{
if (resolvedEvent.OriginalEvent.EventType.StartsWith("$") || resolvedEvent.OriginalEvent.EventStreamId.StartsWith("$"))
return;
var @event = EventSerialization.DeserializeEvent(resolvedEvent.OriginalEvent);
if (@event != null)
{
var eventType = @event.GetType();
if (_eventHandlerMapping.ContainsKey(eventType))
{
var task = Task.Factory.StartNew(() => _eventHandlerMapping[eventType](event));
Console.WriteLine("The task is running asynchronously...");
}
}
if (resolvedEvent.OriginalPosition != null) _latestPosition = resolvedEvent.OriginalPosition.Value;
}
private void HandleSubscriptionDropped(EventStoreCatchUpSubscription subscription, SubscriptionDropReason dropReason, Exception ex)
{
if (dropReason == SubscriptionDropReason.ProcessingQueueOverflow)
{
//TODO: Wait and reconnect probably with back off
}
if (dropReason == SubscriptionDropReason.UserInitiated)
return;
if (SubscriptionDropMayBeRecoverable(dropReason))
{
Start();
}
}
private static bool SubscriptionDropMayBeRecoverable(SubscriptionDropReason dropReason)
{
return dropReason == SubscriptionDropReason.Unknown || dropReason == SubscriptionDropReason.SubscribingError ||
dropReason == SubscriptionDropReason.ServerError || dropReason == SubscriptionDropReason.ConnectionClosed;
}
private static void LiveProcessingStarted(EventStoreCatchUpSubscription eventStoreCatchUpSubscription)
{
}
}
}
更好吗?您有一个
eventoccurrend
委托,在该委托中,您将收到EventStore中发生的所有事件的通知
首先考虑在一个不同的调度器中运行代码> > EndoCults<代码>。
其次,您是否可以将其更改为一个带有FakeEventBase
实现的抽象类
,然后扩展它并为每个FakeEvent
类型创建单独的实例。
这将是一个更干净的解决方案。
第三,考虑一个自定义<代码>线程调度程序< /代码>,用于排队和运行这些<代码>句柄< /代码>任务。
编辑:
我会有一个像下面这样的播音员类,它知道操作何时完成并引发已完成事件
public class EventBroadcaster
{
public event EventHandler SomeEventOccured;
public async void DoLongRunningOperationAndRaiseFinishedEvent()
{
var waitingTask = Task.Delay(TimeSpan.FromSeconds(2));
await waitingTask.ContinueWith(t => RaiseSomeEventOccured(), CancellationToken.None,
TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.Current);
}
private void RaiseSomeEventOccured()
{
EventHandler handler = SomeEventOccured;
if (handler != null) handler(this, EventArgs.Empty);
}
}
然后是一个EventListener
public class EventListner
{
private readonly string _id;
public EventListner(string id)
{
_id = id;
}
public void ListenTo(EventBroadcaster broadcaster)
{
broadcaster.SomeEventOccured += OnSomeEventOccured;
}
private async void OnSomeEventOccured(object sender, EventArgs eventArgs)
{
var currentTime = DateTime.Now;
Console.WriteLine("EventListner {0} received at {1}", _id,
currentTime.ToString("dd-MM-yyyy HH:mm:ss.fffffff"));
//Not required just to show this does not affect other instances.
//await Task.Delay(TimeSpan.FromSeconds(5));
}
}
然后这将是用于测试的Program.cs
public static class Program
{
public static void Main(string[] args)
{
var broadcaster = new EventBroadcaster();
var listners = new List<EventListner>();
for (int i = 1; i < 10; i++)
{
var listner = new EventListner(i.ToString(CultureInfo.InvariantCulture));
listner.ListenTo(broadcaster);
listners.Add(listner);
}
broadcaster.DoLongRunningOperationAndRaiseFinishedEvent();
Console.WriteLine("Waiting for operation to complete");
Console.ReadLine();
}
}
现在您将看到事件是以随机顺序触发的。
我使用选项1获得了更好的性能。
注意:始终使用TPL
和Parallel
编程,您需要确保在使用它之前有好处。我真的不认为创建并行事件订阅服务器有什么意义(如果我理解您的意图正确-能够并行运行事件处理程序,而不是像正常事件那样一个接一个地运行事件处理程序)
如果事件处理程序本身显示了并行运行的意图,那么表达并行运行的意图就更加清楚了
有点像(非常原始)
您可能想创建一种管理器(老实说,我不知道如何占用所有核心,但我不认为这很复杂,我只是从来没有必要这么做),但请保留正常事件。我没有进行全面审查,但我的第一个批评是避免使用名为“@event”的变量。即使使用@前缀是完全合法的,也很难看。仅适用于针对数据源(db、ws…)生成的代码,不适用于“常规”代码。我知道,这对主题没什么帮助,对不起。没有.NET5这样的东西。当前版本为.NET 4.5.2,即将发布的版本(Visual Studio 2015)为.NET 4.6。你是否混淆了.NET版本号和C#版本?就我个人而言,我发现很难阅读整个代码,也很难理解你的意图。请你举一个小的例子,并对你的问题更具体一点。用几句话、一个小例子和你想知道哪些可以改进/是问题的事情来描述你目前的方法。。等等,你看过Rx()了吗。它可能正是你所要寻找的。不管出于什么原因,看到有人要求删除合并,真是好笑。。。这些电话似乎非常合法,清楚地说明为什么他们不合法会使事情变得更加清楚!对不起,你的回答没有道理。为什么某些EventSubscriber应该实现FakeEventBase?也不知道为什么我应该在这样一个简单的场景中实现一个定制的ThreadScheduler…您希望事件能够并行处理如果您有多个侦听器,那么事件可以并行处理。想象一个交通信号灯,有多辆车在信号灯中等待绿灯
,然后所有车辆根据前面的交通情况做出移动的决定;在您的情况下,eventOccursed
不会同时广播给所有处理程序,而是eventOccursed
一个接一个地分派它们,尽管异步地希望您能得到不同。另外,我建议使用一个单独的ThreadPool
,因为我认为您不希望在主线程池中进行均匀处理如果另一个线程池已经有任务排队,这可能会导致延迟。请提供一些可供选择的代码,以便同时向所有处理程序广播。好的,您可以建议对此主题的改进吗?谢谢。我想如果特定eventhandler的事件发生得非常快,您的建议会利用内核。这与我尝试在更高级别(即在SomeEventSubscriber中)利用内核形成对比。问题是什么更具可伸缩性。。。
public static class Program
{
public static void Main(string[] args)
{
var broadcaster = new EventBroadcaster();
var listners = new List<EventListner>();
for (int i = 1; i < 10; i++)
{
var listner = new EventListner(i.ToString(CultureInfo.InvariantCulture));
listner.ListenTo(broadcaster);
listners.Add(listner);
}
broadcaster.DoLongRunningOperationAndRaiseFinishedEvent();
Console.WriteLine("Waiting for operation to complete");
Console.ReadLine();
}
}
private void RaiseSomeEventOccured()
{
Action handler = SomeEventOccured;
if (handler != null)
{
var parallelOption = new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount };
Parallel.Invoke(parallelOption, Array.ConvertAll(handler.GetInvocationList(), ConvertToAction));
handler();
}
}
private Action ConvertToAction(Delegate del)
{
return (Action)del;
}
void SomeEventHandler(object sender, EventArgs e)
{
Task.Run(() =>
{
... // some code to run in parallel
});
}