У меня есть событие, при котором подписчики выполняют код БД, который может занять некоторое время, чтобы вернуться. Я хочу выполнить все подписчики делегатов параллельно. Я пытаюсь использовать 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());
}
}