使用Parallel.ForEach 在Parallel.ForEach外部设置bool

时间:2021-03-06 13:51:12

I'd like to use the power of Parallel.ForEach on a List<T> for a validation routine. The List is iterated to ensure a property is not < 1. A bool is created that is set to false if validation finds an error which is returned in the validation method call. I've been told that this code is problematic as bool is a primitive and not thread safe. Is there a way I can harness of the power of Parallel.ForEach on a server with a lot of cores and RAM and ensure this works properly concerning thread safety?

我想在List 上使用Parallel.ForEach的强大功能来验证例程。迭代List以确保属性不是<1。如果验证发现验证方法调用中返回的错误,则创建bool,将其设置为false。我被告知这个代码是有问题的,因为bool是一个原始的而不是线程安全的。有没有一种方法可以在具有大量内核和RAM的服务器上利用Parallel.ForEach的强大功能并确保其在线程安全方面正常工作?

public static bool IsValid(List<Airport> entities)
{
    bool isValid = true;

    Parallel.ForEach<Airport>(entities, entity =>
    {
        // userId can't be less than 1
        if (entity.userId < 1)
        {
            SiAuto.Main.LogMessage("Airport {0}: invalid userId {1}", entity.airportId, entity.userId);
            isValid = false;
            System.Diagnostics.Debugger.Break();
        }
    });

    return isValid;
}

2 个解决方案

#1


3  

You can do that with PLINQ:

你可以用PLINQ做到这一点:

public static bool IsValid(List<Airport> entities)
{
    return !entities.AsParallel().Any(entity => entity.UserId < 1);
}

However, since the part running in parallel is so small you'll get no improvement so you should stick with the regular foreach (or LINQ):

但是,由于并行运行的部分非常小,所以你没有任何改进,所以你应该坚持使用常规的foreach(或LINQ):

public static bool IsValid(List<Airport> entities)
{
    return !entities.Any(entity => entity.UserId < 1);
}

#2


1  

If the list is big enough, I'd go with a PLINQ approach using Enumerable.Any or Enumerable.All:

如果列表足够大,我会使用Enumerable.Any或Enumerable.All来使用PLINQ方法:

return !entities.AsParallel().Any(x => x.UserId < 1);

Or

要么

return entities.AsParallel().All(x => !(x.UserId < 1));

Usually when a pipeline style execution is used, I find PLINQ more suitable than the Parallel class as it removed the need to update a shared resource inside your parallel loop.

通常在使用管道样式执行时,我发现PLINQ比Parallel类更合适,因为它消除了更新并行循环内共享资源的需要。

Note you should benchmark your code to make sure parallelism is worth it. In many cases, if the list isn't big enough, this may de-grade performance.

请注意,您应该对代码进行基准测试,以确保并行性是值得的。在许多情况下,如果列表不够大,这可能会降低性能。

#1


3  

You can do that with PLINQ:

你可以用PLINQ做到这一点:

public static bool IsValid(List<Airport> entities)
{
    return !entities.AsParallel().Any(entity => entity.UserId < 1);
}

However, since the part running in parallel is so small you'll get no improvement so you should stick with the regular foreach (or LINQ):

但是,由于并行运行的部分非常小,所以你没有任何改进,所以你应该坚持使用常规的foreach(或LINQ):

public static bool IsValid(List<Airport> entities)
{
    return !entities.Any(entity => entity.UserId < 1);
}

#2


1  

If the list is big enough, I'd go with a PLINQ approach using Enumerable.Any or Enumerable.All:

如果列表足够大,我会使用Enumerable.Any或Enumerable.All来使用PLINQ方法:

return !entities.AsParallel().Any(x => x.UserId < 1);

Or

要么

return entities.AsParallel().All(x => !(x.UserId < 1));

Usually when a pipeline style execution is used, I find PLINQ more suitable than the Parallel class as it removed the need to update a shared resource inside your parallel loop.

通常在使用管道样式执行时,我发现PLINQ比Parallel类更合适,因为它消除了更新并行循环内共享资源的需要。

Note you should benchmark your code to make sure parallelism is worth it. In many cases, if the list isn't big enough, this may de-grade performance.

请注意,您应该对代码进行基准测试,以确保并行性是值得的。在许多情况下,如果列表不够大,这可能会降低性能。