在C#中将多个Parallel.ForEach合并为一个

3

Parallel.ForEach会阻塞直到所有线程返回。下面的每个objectType实际上都是一个列表。在这种情况下,有没有办法只使用一次Parallel.ForEach?请给予建议。

Main(){
    List<Type1> objectType1 = ...
        List<Type2> objectType2 = ...
        List<Type3> objectType3 = ...

    Parallel.ForEach(objectType1, MyFunction)
    Parallel.ForEach(objectType2, MyFunction)
    Parallel.ForEach(objectType3, MyFunction)
}

这是我的函数:


MyFunction (object arg) {

    //some code here

    if (arg is Type1) { ProcessType1(arg as Type1); }

    else if (arg is Type2) { ProcessType2(arg as Type2); }

    else if (arg is Type3) { ProcessType3(arg as Type3); }

    //some more code here
}

1
在每种情况下,“MyFunction”都是相同的函数吗? - Merlyn Morgan-Graham
1
MyFunction 操作的是什么类型?如果它们都操作相同的类型,请将列表合并为一个列表,并在每个项目上调用 Parallel.ForEach。 - Judah Gabriel Himango
1
小提示:可以使用以下代码替代“is”和“as”:“var t1 = arg as Type1; if(arg!= null)ProcessType1(t1);” - Michael Stum
3个回答

6

对于你上面编写的伪代码,Type1Type2Type3都必须可以转换为一个共同的类型,这个类型是MyFunction方法的参数类型。如果它们都有一个共同的基础类型,并且你确实调用了MyFunction方法来处理它们,那么你可以使用LINQ组合这些序列:

Parallel.ForEach(objectType1.Concat<BaseType>(objectType2).Concat(objectType3),
    MyFunction);

并且MyFunction的样式如下:

public void MyFunction(BaseType baseType)
{
    // Process base type...
}

你甚至可以使用 object 作为公共基础类型,但那样会有一些丑陋的强制转换。 - Michael Stum

1
你可以将它们转换为对象并使用 Concat 进行组合。
List<object> combined = one.Cast<object>()
    .Concat<object>(two.Cast<object>())
    .Concat(three.Cast<object>())
    .ToList();

我还要指出,像那样使用反射可能表明了一些糟糕的设计决策。如果可能的话,您应该提取一个每个不同类型都实现的公共接口。例如,像这样的东西:
interface IProcessable
{
    void Process();
}

class Type1 : IProcessable
{
    public void Process(){ //stuff }
}

class Type2 : IProcessable
{
    public void Process(){ //stuff }
}

那么你只需有一个IEnumerable<IProcessable>,然后执行以下操作:

Parallel.Foreach(listOfStuff, Process);

1
你需要进行连接操作。具体的方式取决于Type01Type02Type03的类型。我将假设它们是自定义类,因此你可以这样做:
public class X { }
public class Y { }
public class Z { }

static void Main(string[] args)
{
    var l1 = new List<X> { new X() };
    var l2 = new List<Y> { new Y() };
    var l3 = new List<Z> { new Z() };

    var master = new List<dynamic>();

    master.AddRange(l1);
    master.AddRange(l2);
    master.AddRange(l3);

    Parallel.ForEach(master,
        val =>
        {
            var isX = val is X;
        });
}

如果你的问题是重复相同的函数,那么你可以将函数体存储到 Action<dynamic> 中。
Action<dynamic> action =
    (val) =>
    {
        var isX = val is X;
    };

并调用

Parallel.ForEach(yourList, action);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接