Обработка исключений не работает в Parallel.ForEach - PullRequest
1 голос
/ 07 июня 2011

Проблемная ситуация

В моем проекте я звоню в PowerShell, чтобы получить список организаций, настроенных в Exchange 2010. Затем я должен сделать что-то для каждой организации.Вызов PowerShell sloooow , поэтому, если бы я выполнял все последовательные операции, это заняло бы минуты.Тем не менее, вы можете создать PowerShell Runspace Pool и выполнять команды параллельно, что экономит много времени.Вот что я сделал:

public void MainMethod()
{
    var organizations = exchangeRepository.GetOrganizations();
    Parallel.ForEach(
        organizations,
        organization => 
        {
            try
            {
                exchangeRepository.DoSomethingWithAnOrganization(organization);
            }
            catch (Exception ex)
            {
                ...
            }
        }
    );
}

Задача

Это работает как заклинание с одним исключением.Метод DoSomethingWithAnOrganization имеет функцию try-catch и может обрабатывать некоторые исключения.Однако всякий раз, когда возникает исключение, оно не обрабатывается catch в методе DoSomething, а сразу переходит к оператору catch объекта MainMethod.

(Примечание: оператор catch метода DoSomethingназывается нормально, если я просто использую foreach (... in ...) вместо Parallel.ForEach).

Вопрос

Почему я не могу справитьсяисключение в DoSomething-методе?Есть ли способ сделать DoSomething параллельным по-другому, поэтому при возникновении исключения вызывается перехват этого метода?

Спасибо!


Это метод DoSomething:

public IEnumerable<Mailbox> Invoke(string organizationName)
{
    try
    {
        var command = new PSCommand()
            .AddCommand("Get-Mailbox")
            .AddParameter("Organization", organizationName);

        var result = Invoke(command);

        var mailboxes =
            from mailbox in result.Results
            select new Mailbox() 
            {
                Organization = organizationName,
                Name = (string)mailbox.Properties["Name"].Value,
                Identity = mailbox.Properties["Identity"].Value.ToString(),
                Plan = 
                    mailbox.Properties["MailboxPlan"].Value == null
                    ? null
                    : (string)mailbox.Properties["MailboxPlan"].Value
                    .GetType().GetProperty("Name")
                    .GetValue(mailbox.Properties["MailboxPlan"].Value, null),
            };
        return mailboxes;
    }
    catch (Exception ex)
    {
        Log.Error(ex.Message, ex);
        throw new Exceptions.ReportingServiceException(Exceptions.ExceptionType.Technical, ex.Message, ex);
    }
}

Ответы [ 2 ]

0 голосов
/ 10 июня 2011

Рефакторинг MainMethod для:

var organizations = ExchangeRepository.GetOrganizations().AsParallel();
var someInfo = organizations.SelectMany(organization => ExchangeRepository.DoSomethingWithOrganization(organization.Name));

и теперь вызывается улов в методе DoSomething. Я не знаю, почему это работает так и почему это не так.

0 голосов
/ 07 июня 2011

Не видя ваш код, я предполагаю, что если код работает последовательно (один поток), а не параллельно (несколько потоков), то вы получите исключение, которого DoSomethingWithAnOrganisation не ожидал (по крайней мере, как последовательная операция) но теперь вы работаете параллельно.

Вы делитесь exchangeRepository между задачами (потоками), и если оно содержит изменяемое состояние, то это может быть причиной проблемы. Вы не можете изменить общие данные / состояние между потоками, не синхронизируя доступ к этим данным / состоянию с блокировками. Часто вы обнаружите, что вы можете добиться гораздо более высокой производительности, если реорганизуете свой код для работы без общего состояния, чем пытаясь синхронизировать код - что является узким местом в многопоточном коде.

Если вы сможете ответить на вопросы, которые я задавал выше, я мог бы дать вам более конкретный ответ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...