[英]how can I handle an event in parallel in C# and TPL
我有一个事件,当被触发时,订阅者会执行一些可能需要一段时间才能返回的数据库代码。 我想并行执行所有订阅者委托。 我正在尝试使用 Parallel.Foreach 但我无法完全正确地使用任何建议?
我目前正在尝试按照这些方式做一些事情。
Parallel.ForEach(FacilitiesChanged.GetInvocationList(),某种 lambda 表达式)
其中,设施变更是一个事件。
我有一个事件,当被触发时,订阅者会执行一些可能需要一段时间才能返回的数据库代码。 我想并行执行所有订阅者委托。 我正在尝试使用 Parallel.Foreach 但我无法完全正确地使用任何建议?
我建议将并行性推入订阅者一侧,而不是尝试并行调用委托。
只需让订阅者执行以下操作:
private void OnMyEvent(object sender, EventArgs e)
{
Task.Factory.StartNew( () =>
{
// Your DB code logic here...
});
}
这将导致事件异步发生。
如果您必须等待返回类型,我个人会避免一起发生事件。 这里的问题是有一个固有的期望,即事件订阅者不会阻塞。 允许事件阻塞将违反预期,并导致问题。
相反,我建议使用控制反转的形式,并通过接口而不是事件来处理它。 这将成为观察者模式与标准事件用法有些不同的变体:
// Publisher side - add methods to add/remove "subscribers":
public void AddListener(IDatabaseOperation op)
{
lock(syncObj) // thread safety may be an issue...
this.listeners.Add(op);
}
private void OnEvent()
{
lock(syncObj)
{
Parallel.ForEach(this.listeners, l => l.DoOperation());
}
}
如果您必须在发布端多线程调用,可以通过以下方式完成:
private void RaiseMyEvent(MyEventArgs e)
{
var handler = this.TheEvent;
if (handler != null)
{
var tasks = new List<Task>();
foreach(var yourEvent in handler.GetInvocationList().Cast<EventHandler<MyEventArgs>())
tasks.Add(Task.Factory.StartNew( () => yourEvent(this, e)));
// Optionally wait here... Removing the following makes this asynchronous
Task.WaitAll(tasks.ToArray());
}
}
您可以使用Reactive Extensions在接收到事件时对任务进行排队。 Reactive Extensions 中有一些漂亮且有用的功能。
执行“全部并行”可能不是您想要的。 您可以改为尝试手动控制 Parallel.ForEach 使用的分派线程数。
如果您有很多等待时间,那么您可能想要设计应用程序以使用异步数据库操作。 请记住,如果 SQL 服务器必须使用“太多线程”,它会变慢。
如果您知道在调用时要执行哪些操作,则可以使用 Parallel.For。 但据我所知,每次事件发生时,您都想触发一些数据库操作。
所以,我会使用一个队列来存储“事件请求”。 第二个线程(或 BackgroundWorker)可以监视队列并执行存储在其中的操作。
切里奥,克里斯
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.