代码之家  ›  专栏  ›  技术社区  ›  cdiggins

多个线程减慢了字典的整体访问速度?

  •  1
  • cdiggins  · 技术社区  · 14 年前

    我正在分析一个C应用程序,它看起来每个调用有两个线程 Dictionary<>.ContainsKey() 在两个独立但相同的字典(只有两个项目)上,每个字典的5000次调用速度是一个线程调用速度的两倍。 字典<>.containsKey()) 在一本字典上写上10000次。

    我正在使用一个叫做JetBrains Dottrace的工具来测量“线程时间”。我显式地使用相同数据的副本,因此没有我使用的同步化原语。.NET是否有可能在后台进行某些同步?

    我有一个双核机器,有三个线程在运行:一个线程被阻塞使用 Semaphore.WaitAll() 当工作在优先级设置为的两个新线程上完成时 ThreadPriority.Highest .

    明显的罪魁祸首,比如,没有并行运行代码,也没有使用发布版本,已经被排除在外。

    编辑:

    人们需要密码。那么好吧:

        private int ReduceArrayIteration(VM vm, HeronValue[] input, int begin, int cnt)
        {
            if (cnt <= 1)
                return cnt;
    
            int cur = begin;
    
            for (int i=0; i < cnt - 1; i += 2)
            {
                // The next two calls are effectively dominated by a call 
                // to dictionary ContainsKey
                vm.SetVar(a, input[begin + i]);
                vm.SetVar(b, input[begin + i + 1]);
                input[cur++] = vm.Eval(expr);
            }
    
            if (cnt % 2 == 1)
            {
                input[cur++] = input[begin + cnt - 1];
            }
    
            int r = cur - begin;
            Debug.Assert(r >= 1);
            Debug.Assert(r < cnt);
            return r;
        }
    
        // From VM
        public void SetVar(string s, HeronValue o)
        {
            Debug.Assert(o != null);
            frames.Peek().SetVar(s, o);
        }
    
        // From Frame
        public bool SetVar(string s, HeronValue o)
        {
            for (int i = scopes.Count; i > 0; --i)
            {
                // Scope is a derived class of Dictionary
                Scope tbl = scopes[i - 1];
                if (tbl.HasName(s))
                {
                    tbl[s] = o;
                    return false;
                }
            }
            return false;
        }
    

    下面是线程生成代码,可能会延迟:

    public static class WorkSplitter
    {
        static WaitHandle[] signals;
    
        public static void ThreadStarter(Object o)
        {
            Task task = o as Task;
            task.Run();
        }
    
        public static void SplitWork(List<Task> tasks)
        {
            signals = new WaitHandle[tasks.Count];
            for (int i = 0; i < tasks.Count; ++i)
                signals[i] = tasks[i].done;
            for (int i = 0; i < tasks.Count; ++i)
            {
                Thread t = new Thread(ThreadStarter);
                t.Priority = ThreadPriority.Highest;
                t.Start(tasks[i]);
            }
            Semaphore.WaitAll(signals);
        }        
    }
    
    1 回复  |  直到 14 年前
        1
  •  4
  •   Hans Passant    14 年前

    即使字典中有任何锁(没有),它也不会影响您的测量,因为每个线程都使用一个单独的线程。运行这个测试10000次还不足以获得可靠的定时数据,containsKey()只需要20纳秒左右。您至少需要几百万次来避免调度工件。