Как я могу обрабатывать событие параллельно в C # и TPL - PullRequest
1 голос
/ 21 февраля 2011

У меня есть событие, при котором подписчики выполняют код БД, который может занять некоторое время, чтобы вернуться. Я хочу выполнить все подписчики делегатов параллельно. Я пытаюсь использовать Parallel.Foreach, но я не совсем понимаю, какие-либо предложения?

Я сейчас пытаюсь сделать что-то в этом роде.

Parallel.ForEach (FacilitiesChanged.GetInvocationList (), какое-то лямбда-выражение)

, где FacilitiesChanged - событие.

Ответы [ 3 ]

5 голосов
/ 21 февраля 2011

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

вы можете использовать Parallel.For, если вы знаете, какие действия вы хотите выполнить при вызове.Но, как я понимаю, вы хотите запускать некоторые действия БД каждый раз, когда происходит событие.

Итак, я бы использовал Очередь для хранения «Запроса на событие».Второй поток (или BackgroundWorker) может наблюдать за очередью и выполнять сохраненные в ней действия.

cherio, Крис

0 голосов
/ 21 февраля 2011

Вы можете использовать Reactive Extensions , чтобы ставить задачи в очередь при получении событий.В них есть некоторые изящные и полезные функции Reactive Extensions.

Выполнение «все параллельно», вероятно, не то, что вам нужно.Вместо этого вы можете попытаться вручную управлять тем, как много потоков диспетчеризации Parallel.ForEach использует.

Если у вас много времени ожидания, вам может потребоваться настроить приложение на использование * 1009.* асинхронные операции с БД .Просто помните, что сервер SQL замедлится, если ему придется использовать «слишком много потоков».

...