好的,在System.Threading.Tasks中使用.Net 4.0 Parellel Extensions。我发现了什么似乎奇怪的行为,但我认为我做错了。我有一个界面和几个实现条款,它们很简单。
interface IParallelPipe
{
void Process(ref BlockingCollection<Stream> stream, long stageId);
}
class A:IParallelPipe
{
public void Process(ref BlockingCollection<Stream> stream, long stageId)
{
//do stuff
}
}
class B:IParallelPipe
{
public void Process(ref BlockingCollection<Stream> stream, long stageId)
{
//do stuff
}
}
然后我的班级就这些开始了。这就是出现问题的地方。我基本上从传入的类型中获取有关要调用的实现类的信息,然后调用工厂来实例化它,然后用它创建一个任务并启动它。如图所示:
BlockingCollection<Stream> bcs = new BlockingCollection<Stream>();
foreach (Stage s in pipeline.Stages)
{
IParallelPipe p = (IParallelPipe)Factory.GetPipe(s.type);
Task.Factory.StartNew(() => p.Process(ref bcs, s.id));
}
在我的示例的每次运行中,pipeline.Stages包含两个元素,一个被实例化为A类,另一个被视为B类。这很好,我在te调试器中看到它随着两个元素的消失不同种类。但是,B类永远不会被调用,而是我得到两个A.Process(...)方法的调用。两者都包含传入的stageId(即两个调用具有不同的stageIds)。
现在,如果我把一些东西分开来,只是为了测试我可以通过做这样的事情来使事情发挥作用:
BlockingCollection<Stream> bcs = new BlockingCollection<Stream>();
A a = null;
B b = null;
foreach (Stage s in pipeline.Stages)
{
IParallelPipe p = (IParallelPipe)Factory.GetPipe(s.type);
if(p is A)
a = p;
else
b = p;
}
Task.Factory.StartNew(() => a.Process(ref bcs, idThatINeed));
Task.Factory.StartNew(() => b.Process(ref bcs, idThatINeed));
这会调用相应的类!
有什么想法???
答案 0 :(得分:4)
您所描述的行为对我来说似乎很奇怪 - 我希望使用正确的实例,但可能会使用错误的阶段ID - old foreach
variable capture问题。正在捕获变量s
,并且在任务工厂评估闭包时,s
的值已更改。
这绝对是您的代码中的一个问题,但它并不能解释您遇到问题的原因。只是为了检查,你真的 在循环中声明p
,而不是在它之外?如果你在循环之外声明p
,这将解释所有内容。
以下是捕获问题的解决方法:
BlockingCollection<Stream> bcs = new BlockingCollection<Stream>();
foreach (Stage s in pipeline.Stages)
{
Stage copy = s;
IParallelPipe p = (IParallelPipe)Factory.GetPipe(s.type);
Task.Factory.StartNew(() => p.Process(ref bcs, copy.id));
}
请注意,我们只是在循环中复制并捕获该副本,以便每次都获得变量的不同“实例”。
或者,我们可以只捕获ID,而不是捕捉舞台,而不是我们需要的所有内容:
BlockingCollection<Stream> bcs = new BlockingCollection<Stream>();
foreach (Stage s in pipeline.Stages)
{
long id = s.id;
IParallelPipe p = (IParallelPipe)Factory.GetPipe(s.type);
Task.Factory.StartNew(() => p.Process(ref bcs, id));
}
如果这没有帮助,你能发布一个简短但完整的程序来证明这个问题吗?这样可以更容易追踪。