我有一个事件,当被解雇时,订阅者执行一些可能需要一段时间才能返回的数据库代码。我想并行执行所有订阅者委托。我正在尝试使用Parallel.Foreach,但我无法提出任何建议吗?
我目前正在尝试沿着这些方向做点什么。
Parallel.ForEach(FacilitiesChanged.GetInvocationList(),某种lambda表达式)
其中,FacilitiesChanged是一个事件。
答案 0 :(得分:5)
我有一个事件,当被解雇时,订阅者执行一些可能需要一段时间才能返回的数据库代码。我想并行执行所有订阅者委托。我正在尝试使用Parallel.Foreach,但我无法提出任何建议吗?
我建议将并行性推送到订阅者端,而不是尝试并行调用委托。
让订阅者做:
private void OnMyEvent(object sender, EventArgs e)
{
Task.Factory.StartNew( () =>
{
// Your DB code logic here...
});
}
这将导致事件异步发生。
如果你必须等待返回类型,我个人会一起避免事件。这里的问题是事件订户不会阻止固有的期望。允许事件阻止将违反预期,并导致问题。
相反,我建议使用一种控制反转形式,并通过接口而不是事件来处理。然后,这变为Observer Pattern与标准事件使用情况稍有不同的变体:
// 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());
}
}
答案 1 :(得分:0)
您可以使用Reactive Extensions在接收事件时对任务进行排队。 Reactive Extensions中有一些非常有用的功能。
执行“all all parallel”可能不是你想要的。您可以尝试手动控制Parallel {ForEach many dispatch threads使用的方式。
如果你有很多等待时间,那么你可能想要的是设计你的应用程序以使用async DB operations。请记住,如果必须使用“太多线程”,SQL服务器将会变慢。
答案 2 :(得分:0)
您可以使用Parallel.For,如果您知道在调用时要执行哪些操作。但据我了解,您希望每次事件发生时触发一些数据库操作。
所以,我会用一个队列来存储“事件请求”。第二个线程(或BackgroundWorker)可以观察队列并执行存储在那里的操作。
cherio, 克里斯