Разница между копированием ссылки на класс и копированием значения - PullRequest
0 голосов
/ 11 сентября 2018

Для эксперимента я попробовал это:

(1) Создайте 100000 классов, каждый из которых оборачивает двойную переменную

--- Это часть эксперимента ---

(2) Измерение производительности двух методов путем запуска 100000 раз:

  • создайте двойное [] и присвойте значение переносимым переменным.

  • создайте класс [] и назначьте ссылку на класс обтекания.

Вышеприведенное может вас смущать, поэтому я прилагаю код:

static void Main(string[] args)
{
    int length = 100000;
    Test test = new Test(length);

    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();

    for (int i = 0; i < length; i++)
        test.CopyValue();
        //test.CopyReference(); //test.CopyValue(); or test.CopyReference();

    stopwatch.Stop();
    Console.WriteLine("RunTime : {0} ", stopwatch.ElapsedMilliseconds);
}

class DoubleWrapper
{
    public double value = 0.0;
}

class Test
{
    DoubleWrapper[] wrapper;

    public void CopyValue()
    {
        double[] x = new double[wrapper.Length];
        for (int i = 0; i < wrapper.Length; i++)
            x[i] = wrapper[i].value;
    }

    public void CopyReference()
    {
        DoubleWrapper[] x = new DoubleWrapper[wrapper.Length];
        for (int i = 0; i < wrapper.Length; i++)
            x[i] = wrapper[i];
    }

    public Test(int length)
    {
        wrapper = new DoubleWrapper[length];
        for (int i = 0; i < length; i++)
            wrapper[i] = new DoubleWrapper();
    }
}

Результат выглядит следующим образом:

test.CopyValue (): 56890 (миллисекунда)

test.CopyReference (): 66688 (миллисекунда)

(построено с конфигурацией выпускаи побежал exe)

Я пробовал несколько раз, но результат не сильно меняется.Поэтому я пришел к выводу, что CopyReference () занимает больше времени.


Но я с трудом понимаю, почему.Вот вопрос:

Я думал, что, независимо от CopyValue () или CopyReference (), моя машина выполняет «Копирование числа в памяти», хотя одно - двойное значение, а другое - ссылка на класс,Так что не должно быть значимой разницы в производительности, но факт не в этом.

Тогда в чем разница между копированием значения и копированием ссылки?Копирование ссылки делает больше, чем копирование значения?

(При передаче ссылки без ключевого слова ref не правда ли, что ссылка копируется, как если бы она была значением? Что я говорю, так это,

ClassA x = new ClassA();
ClassA y = x;

означает создание копии «ссылки на x», а затем присвоение переменной y, следовательно, y = null вообще не влияет на x. Это правда?)

Если яЯ работаю с неверными предположениями, пожалуйста, дайте мне знать, в чем я не прав.

Я ценю вашу помощь и совет.

-

Я догадался, что GC может оказать какое-то влияние, но отключение GC с помощью TryStartNoGCRegion (Int64) не меняет вывод.(оба становятся быстрее, но все же CopyReference () медленнее.)

Ответы [ 2 ]

0 голосов
/ 11 сентября 2018

Чтение о стеке и куче может помочь вам понять.если вы копируете ссылку, вы по сути копируете указатель, показывающий фактический объект в куче, и если этот фактический объект изменяется, эти изменения отображаются на каждой вещи, которая ссылается на этот объект.

Если вы выполните "глубокая копия "или клон (как при реализации IClonable), вы продублируете эти данные в стеке и создадите указатель на него, таким образом, больше не зависите от исходного объекта.

Надеюсь, это объяснение поможетты немного?См. Это для получения дополнительной информации https://www.c -sharpcorner.com / article / C-Sharp-heaping-vs-stacking-in-net-part-i / в стеке и куче.

0 голосов
/ 11 сентября 2018

означает создание копии «ссылки на x», а затем присвоение переменной y, следовательно, y = null не влияет на x вообще.Это правда?

Это верно - вы сделали копию ссылки.

Теперь, как насчет того, почему ваша реализация CopyReference медленнее?

Вы должны выполнить анализ производительности, чтобы получить реальное представление об этом, но у меня в голове:

Вы создаете новый экземпляр DoubleWrapper ссылочный тип внутри этого метода.Помните, что C# не является языком "абстракции с нулевой стоимостью", как, например, C/C++/Rust.Создание экземпляра, даже простого ссылочного типа, который делает не более чем простую оболочку над примитивным типом, может стоить вам дороже.Поскольку в этом экземпляре содержится больше, чем простое значение double, размер объекта DoubleWrapper не будет равен 8 байтам.

...