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

时间:2010-02-06 04:02:24

标签: c# .net performance multithreading

我正在分析一个C#应用程序,它看起来像两个线程,每个调用Dictionary<>.ContainsKey() 5000个时间,两个单独但相同的字典(只有两个项目)是一个线程调用Dictionary<>.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 个答案:

答案 0 :(得分:4)

即使在Dictionary中有任何锁定(没有),它也不会影响您的测量,因为每个线程都使用单独的一个。运行此测试10,000次不足以获得可靠的计时数据,ContainsKey()只需要20纳秒左右。您至少需要几百万次才能避免计划工件。