问题情况
在我的项目中,我调用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,可以处理一些异常。但是,每当发生异常时,它都不会被DoSomething方法中的catch处理,而是立即jups到MainMethod的catch语句。
(注意:如果我简单地使用foreach(... in ...)而不是Parallel.ForEach,那么DoSomething方法的catch语句称为罚款。
问题
为什么我不能在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);
}
}
答案 0 :(得分:0)
在没有看到你的代码的情况下,我猜测如果代码在顺序(单线程)中工作但不在并行(多线程)中,那么你会得到DoSomethingWithAnOrganisation没有预料到的异常(至少作为顺序操作)但是现在你正在并行运行它。
您在任务(线程)之间共享exchangeRepository
,如果包含可变状态,则可能是导致问题的原因。如果没有使用锁同步对该数据/状态的访问,则不能在线程之间改变共享数据/状态。通常,您会发现通过重构代码以便在没有共享状态的情况下工作可以获得更好的性能,而不是尝试同步代码 - 这是多线程代码中的瓶颈。
如果你能回答我上面提出的问题,那么我可能会给你一个更具体的答案。
答案 1 :(得分:0)
我将MainMethod重构为:
var organizations = ExchangeRepository.GetOrganizations().AsParallel();
var someInfo = organizations.SelectMany(organization => ExchangeRepository.DoSomethingWithOrganization(organization.Name));
现在调用了DoSomething-method IS中的catch。我不知道为什么它会以这种方式工作,为什么它没有其他方式。