Производительность - использование объекта Guid или строки Guid в качестве ключа - PullRequest
49 голосов
/ 03 апреля 2009

При использовании Guid в качестве индекса для Dictionary, лучше использовать объект Guid или строковое представление Guid?

Я просто реорганизовал некоторый код, который использовал строку для использования объекта, потому что было повсюду new Guid() вызовов. Но это заставило меня задуматься о проблемах с производительностью. (Коллекции довольно маленькие, но они многократно повторяются.)

Ответы [ 3 ]

80 голосов
/ 03 апреля 2009

Guid должно быть быстрее, так как сравнение проще - всего несколько прямых байтов. Строка включает разыменование и много работы.

Конечно - вы можете профилировать; -p

Данные:

Searching for 7f9b349f-f36f-94de-ad96-04279ddf6ecf
As guid: 466; -1018643328
As string: 512; -1018643328
Searching for 870ba465-08f2-c872-cfc9-b3cc1ffa09de
As guid: 470; 1047183104
As string: 589; 1047183104
Searching for d2376f8a-b8c9-4633-ee8e-9679bb30f918
As guid: 423; 1841649088
As string: 493; 1841649088
Searching for 599889e8-d5fd-3618-4c4f-cb620e6f81bb
As guid: 488; -589561792
As string: 493; -589561792
Searching for fb64821e-c541-45f4-0fd6-1c772189dadf
As guid: 450; 1389733504
As string: 511; 1389733504
Searching for 798b9fe5-ba15-2753-357a-7637161ee48a
As guid: 415; 779298176
As string: 504; 779298176
Searching for 12ba292e-8e59-e5d0-7d04-e811a237dc21
As guid: 457; 558250944
As string: 564; 558250944
Searching for 05b3ce14-dfbf-4d3a-1503-ced515decb81
As guid: 413; 1658205056
As string: 504; 1658205056
Searching for 8db4a556-0a65-d8cb-4d0d-0104245d18b8
As guid: 415; 696231936
As string: 506; 696231936
Searching for c49cf80c-5537-fba5-eebd-8ad21bba09c4
As guid: 459; 2100976384
As string: 557; 2100976384

на основании:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
static class Program
{

    static void Main()
    {
        Random rand = new Random(123456);
        int COUNT = 1000;
        Dictionary<Guid, int> guids = new Dictionary<Guid, int>(COUNT);
        Dictionary<string, int> strings = new Dictionary<string, int>(
            COUNT, StringComparer.Ordinal);

        byte[] buffer = new byte[16];
        for (int i = 0; i < COUNT; i++)
        {
            rand.NextBytes(buffer);
            Guid guid = new Guid(buffer);
            int val = rand.Next();
            guids.Add(guid, val);
            strings.Add(guid.ToString(), val);
        }

        for(int i = 0 ; i < 10 ; i++) {
            int index = rand.Next(COUNT);
            Guid guid = guids.Keys.Skip(index).First();
            Console.WriteLine("Searching for " + guid);
            int chk = 0;
            const int LOOP = 5000000;
            Stopwatch watch = Stopwatch.StartNew();
            for (int j = 0; j < LOOP; j++)
            {
                chk += guids[guid];
            }
            watch.Stop();
            Console.WriteLine("As guid: " + watch.ElapsedMilliseconds
                   + "; " + chk);
            string key = guid.ToString();
            chk = 0;
            watch = Stopwatch.StartNew();
            for (int j = 0; j < LOOP; j++)
            {
                chk += strings[key];
            }
            watch.Stop();
            Console.WriteLine("As string: " + watch.ElapsedMilliseconds
                   + "; " + chk);
        }
        Console.ReadLine();

    }
}
2 голосов
/ 03 апреля 2009

Коллекции довольно маленькие, но многократно повторяются

Если вы выполняете итерацию, нет ключа для сравнения ключей. Если вы добавляете / модифицируете или ищите по ключу, то ключи будут хэшироваться и сравнивать хэши; только если хэши равны, ключи будут сравниваться.

Поэтому, если вы не выполняете много операций на основе ключей в огромных словарях с множеством коллизий хешей, скорость сравнения ключей и ключей не будет основным фактором.

1 голос
/ 03 апреля 2009

Моей первой мыслью было бы, что Guid объекты быстрее, но если вы получаете какой-либо ввод в виде строки и вам нужно искать его в небольшом наборе (hashset) идентификаторов GUID (которые меняются не часто), может быть быстрее хранить их как строки, потому что:

  • Для поиска строки в GUID-словаре необходимо проанализировать строку (включая проверку ошибок и т. Д.), Создать структуру Guid, получить хэш-код, выполнить поиск хеш-функции и выполнить одно окончательное сравнение. байтов GUID.

  • Для поиска строки в String-Dictionary вы должны создать хеш строки (возможно, быстрее, чем построение структуры Guid), найти хэш и выполнить сравнение одной строки. Если, например, вы ожидаете, что многие GUID не будут присутствовать в коллекциях, сравнение хэшей часто будет неудачным, и вам даже не придется выполнять сравнение строк (что занимает немного больше времени, чем сравнение GUID из пункта 1 выше)

Если у вас уже есть структуры Guid в качестве входных данных (например, потому что вы провели некоторую проверку правильности входных строк), конечно, гораздо лучше использовать их в качестве индекса в словаре.

НО : С точки зрения ясности дизайна (что гораздо важнее, чем производительность в 99% всего кода) вы должны использовать Guid структуры и изменять их только в том случае, если вы действительно столкнетесь с проблемы с производительностью (и профилирование показывает, что вы получаете преимущество от строкового решения).

...