C#Parallel Extensions Task.Factory.StartNew在错误的对象上调用方法
好的,在System.Threading.Tasks中使用.Net 4.0并行扩展。我发现了一种奇怪的行为,但我想我是做错了什么。我有一个接口和几个实现类,它们很简单C#Parallel Extensions Task.Factory.StartNew在错误的对象上调用方法,c#,parallel-processing,C#,Parallel Processing,好的,在System.Threading.Tasks中使用.Net 4.0并行扩展。我发现了一种奇怪的行为,但我想我是做错了什么。我有一个接口和几个实现类,它们很简单 interface IParallelPipe { void Process(ref BlockingCollection<Stream> stream, long stageId); } class A:IParallelPipe { public void Process(ref Blocking
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
}
}
接口IParallelPipe
{
void进程(ref BlockingCollection stream,long stageId);
}
A类:IParallelPipe
{
公共作废流程(ref BlockingCollection stream,long stageId)
{
//做事
}
}
B类:IParallelPipe
{
公共作废流程(ref BlockingCollection stream,long stageId)
{
//做事
}
}
然后我让我的班级从这些开始。这就是问题所在。我基本上从传入的类型中获取要调用的实现类的信息,然后调用工厂对其进行实例化,然后用它创建一个任务并启动它。如图所示:
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));
}
BlockingCollection bcs=new BlockingCollection();
foreach(管道中的阶段s。阶段)
{
IParallelPipe p=(IParallelPipe)Factory.GetPipe(s.type);
Task.Factory.StartNew(()=>p.Process(ref-bcs,s.id));
}
在我的示例中的每次运行中,pipeline.Stages都包含两个元素,一个被实例化为类A,另一个被实例化为类B。这很好,我在te调试器中将其视为p,并附带了两种不同的类型。然而,从未调用过类B,而是调用了两次A.Process(…)方法。两者都包含传入的的的stageId(即,两个调用具有不同的stageId)
现在,如果我把事情分开一点,只是为了测试,我可以通过这样做来让事情正常工作:
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));
BlockingCollection bcs=new BlockingCollection();
A=零;
B=零;
foreach(管道中的阶段s。阶段)
{
IParallelPipe p=(IParallelPipe)Factory.GetPipe(s.type);
if(p是A)
a=p;
其他的
b=p;
}
Task.Factory.StartNew(()=>a.Process(ref-bcs,idThatINeed));
Task.Factory.StartNew(()=>b.Process(ref-bcs,idThatINeed));
这将调用相应的类
有什么想法吗 您描述的行为对我来说似乎很奇怪-我希望使用正确的实例,但可能使用错误的阶段ID-问题。正在捕获变量
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));
}
BlockingCollection bcs=new BlockingCollection();
foreach(管道中的阶段s。阶段)
{
阶段拷贝=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));
}
BlockingCollection bcs=new BlockingCollection();
foreach(管道中的阶段s。阶段)
{
长id=s.id;
IParallelPipe p=(IParallelPipe)Factory.GetPipe(s.type);
Task.Factory.StartNew(()=>p.Process(ref-bcs,id));
}
如果这没有帮助,你能发布一个简短但完整的程序来演示这个问题吗?这将使追踪更容易。我认为同样的事情,“这与p无关”,这就是为什么我没有想到foreach问题。不过,我添加了“阶段副本”,问题就解决了。有趣。将进行更多的调查…是的,我在循环中声明p。