返回tolist()的plinq是否是线程安全的? [英] Is the plinq that returning the tolist() is thread safe?

查看:101
本文介绍了返回tolist()的plinq是否是线程安全的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面的代码中,UE是字典,bg是列表。

我使用PLINQ从字典中获取值并返回列表。

是以下代码是线程安全的吗?



TIA



我尝试了什么:



t = UE.AsParallel()。Where(x => bg.Contains(x.Key,StringComparer.OrdinalIgnoreCase))。选择(y => ; y.Value).Distinct()。ToList();

In the below below code UE is dictionary and bg is the list.
I am using PLINQ to get the values from the dictionary and returning the list.
Is the below code is thread safe?

TIA

What I have tried:

t = UE.AsParallel().Where(x => bg.Contains(x.Key, StringComparer.OrdinalIgnoreCase)).Select(y => y.Value).Distinct().ToList();

推荐答案

只要您只是阅读而不修改值,任何东西都是线程安全的。
As long as you're only reading and not modifying values anything is thread safe.


Sascha关于线程安全是正确的。

但是,如果你使用 .AsParallel()来改进性能,你错了!



由于 bg 是一个 List< ; string> .Contains()是一种检查列表成员资格的非常糟糕的方法。它是 O(n)(其中 n bg.Length )。因此整体查询 O(n * m)(其中 m UE.Count )。

相反,您应该从 bg 创建一个 HashSet< string> 并检查该集合中的成员资格。 O(1),使整体查询与 UE.Count 成正比。



使用 HashSet (在我的系统上)<并行扫描 bg

并行化HashSet版本实际上减慢了它的速度,可能是由于并行化设置和上下文切换以及协调开销。

这是我的测试代码:

Sascha is correct about thread safety.
However, if you are using the .AsParallel() to improve performance, you're going about it incorrectly!

Since bg is a List<string>, the .Contains() is a very poor way to check for membership in the list. It is O(n) (where n is bg.Length). So the overall query is O(n*m) (where m is UE.Count).
Instead, you should make a HashSet<string> from bg and check for membership in the set. That is O(1), making the overall query directly proportional to UE.Count.

Using the HashSet is about 100 times faster (on my system) than the parallelized scan of bg.
Parallelizing the HashSet version actually slows it down, presumably due to the parallelization setup and context switching and coordination overhead.
Here's my testing code:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace ConsoleApplication10
{
  class Program
  {
    static void Main(string[] args)
    {
      Random rand = new Random();
      Stopwatch swp = new Stopwatch();
      Stopwatch swh = new Stopwatch();
      Stopwatch swph = new Stopwatch();
      bool tail = false;
      const int count = 200;
      for (int i = 0; i <= count; i++)
      {
        // Populate the collections
        Dictionary<string, int> UE = new Dictionary<string, int>();
        List<string> bg = new List<string>();
        int roff = rand.Next(1000);
        foreach (var item in Enumerable.Range(roff, 10000))
        {
          string key = item.ToString("D");
          UE.Add(key, item % (roff + 500));
          if (item % 10 == 0)
            bg.Add(key);
        }

        // skip timing the first time through so we're sure the JITTER isn't included.
        if (tail)
          swp.Start();
        List<int> tp = UE.AsParallel().Where(x => bg.Contains(x.Key, StringComparer.OrdinalIgnoreCase)).Select(y => y.Value).Distinct().ToList();
        if (tail)
          swp.Stop();

        if (tail)
          swh.Start();
        HashSet<string> hs = new HashSet<string>(bg, StringComparer.OrdinalIgnoreCase);
        List<int> th = UE.Where(x => hs.Contains(x.Key)).Select(y => y.Value).Distinct().ToList();
        if (tail)
          swh.Stop();

        if (tail)
          swph.Start();
        HashSet<string> hps = new HashSet<string>(bg, StringComparer.OrdinalIgnoreCase);
        List<int> tph = UE.AsParallel().Where(x => hps.Contains(x.Key)).Select(y => y.Value).Distinct().ToList();
        if (tail)
          swph.Stop();

        tail = true;

        // so GC of per-timing-iteration garbage isn't included in timing
        UE = null;
        bg = null;
        hs = null;
        hps = null;
        GC.Collect();
      }

      Console.WriteLine("Parallel processing: {0:F2} ticks (avg)", swp.ElapsedTicks / (double)count);
      Console.WriteLine("HashSet processing: {0:F2} ticks (avg)", swh.ElapsedTicks / (double)count);
      Console.WriteLine("Parallel & HashSet processing: {0:F2} ticks (avg)", swph.ElapsedTicks / (double)count);
      Console.WriteLine("Return to exit");
      Console.ReadLine();
    }
  }
}


这篇关于返回tolist()的plinq是否是线程安全的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆