【发布时间】:2013-05-21 23:11:21
【问题描述】:
我有一项服务可以提取电子邮件进行解析。每封电子邮件都由多个访问者解析(都使用一种方法实现了一个简单的IEmailVisitor 接口:void Visit(VisitableEmail email)。对于某些背景上下文,访问者实现包括 SubjectVisitor、BodyVisitor、SummaryVisitor 等。
该服务有一个IList<IEmailVisitor>,它在启动时创建一次,然后以这种方式在计时器事件中重用:
foreach (var email in emailsToParse)
{
foreach (var visitor in _visitors)
{
email.Accept(visitor);
}
}
Email 类有这个方法:public void Accept(IEmailVisitor visitor) { visitor.Visit(this);} 访问每个访问者时,都会在电子邮件实例本身上设置(或更改)属性。
可能有很多电子邮件需要处理。我的问题是,我可以安全地将上面的代码转换为:
Parallel.ForEach(emailsToParse, email =>
{
foreach (var visitor in _visitors)
email.Accept(visitor);
});
在调用Visit(this) 之间,我的访问者都没有维护状态。我确信这个问题反映了我对任务并行性的相当肤浅的了解,但是尽管我一直在阅读,但我不确定这是否是一种安全的方法(假设每次都有足够的电子邮件来证明操作的合理性)。
【问题讨论】:
-
“我的访问者都没有在调用 Visit(this) 之间保持状态”。现在由于正在并行调用 Visit 方法,因此无法使用上述语句来确定它是否安全。您需要提供 Visit 方法内部发生的情况。
-
如果所有访问都设置了 VisitableEmail 的属性并且 IEmailVisitor 上没有任何更改,那么您是安全的。例如,如果您正在设置诸如 Visitor.EmailsCount 等的任何内容,那么您可能会遇到问题。
-
“我的访问者都没有在调用 Visit(this) 之间保持状态。”它如何在该方法的单个调用中保持状态inside?它是否为此使用字段?
-
大部分访问者会从数据库中获取解析(正则)表达式的列表,但是一旦设置,该列表是不可变的,并且对于所有正在访问的电子邮件都是相同的。
-
svick(和 cheedep),我想我明白你现在在问什么了。简短的回答是否定的:状态是在电子邮件本身中维护的。例如,
BodyVisitor有一个私有函数ParseRatings,它接收电子邮件并可能设置其评级。本质上,电子邮件拥有自己的所有状态,并逐渐从访问者到访问者建立起来。
标签: .net task-parallel-library parallel.foreach