Истинная небезопасная производительность кода - PullRequest
21 голосов
/ 21 марта 2011

Я понимаю, что небезопасный код больше подходит для доступа к таким вещам, как API Windows и выполнения небезопасных преобразований типов, чем для написания более производительного кода, но я хотел бы спросить вас, замечали ли вы когда-либо существенное улучшение производительности в реальных приложенияхиспользуя его по сравнению с безопасным кодом C #.

Ответы [ 5 ]

23 голосов
/ 10 июля 2012

Некоторые измерения производительности

Преимущества в производительности не так велики, как вы думаете.

Я провел некоторые измерения производительности нормального доступа к управляемым массивам в сравнении с небезопасными указателями в C #.


Результаты сборки, выполненной вне Visual Studio 2010, .NET 4, с использованием Любой процессор | Выпуск основан на следующей спецификации ПК: ПК на базе x64, 1 четырехъядерный процессор. Intel64 Family 6 Model 23 Stepping 10 GenuineIntel ~ 2833 МГц .

Linear array access
 00:00:07.1053664 for Normal
 00:00:07.1197401 for Unsafe *(p + i)

Linear array access - with pointer increment
 00:00:07.1174493 for Normal
 00:00:10.0015947 for Unsafe (*p++)

Random array access
 00:00:42.5559436 for Normal
 00:00:40.5632554 for Unsafe

Random array access using Parallel.For(), with 4 processors
 00:00:10.6896303 for Normal
 00:00:10.1858376 for Unsafe

Обратите внимание, что небезопасная *(p++) идиома на самом деле работает медленнее. Полагаю, это сломало оптимизацию компилятора, которая сочетала переменную цикла и (сгенерированный компилятором) доступ к указателю в безопасной версии.

Исходный код доступен на github .

15 голосов
/ 21 марта 2011

Как отмечалось в других публикациях, вы можете использовать небезопасный код в очень специализированных контекстах, чтобы получить значительное улучшение производительности.Одним из таких сценариев является перебор массивов типов значений.Использование небезопасной арифметики указателей намного быстрее, чем использование обычного шаблона for-loop / indexer.

struct Foo
{
    int a = 1;
    int b = 2;
    int c = 0;
}

Foo[] fooArray = new Foo[100000];

fixed (Foo* foo = fooArray)  // foo now points to the first element in the array...
{
    var remaining = fooArray.length;
    while (remaining-- > 0)
    {
        foo->c = foo->a + foo->b;
        foo++;  // foo now points to the next element in the array...
    }
}

Основное преимущество заключается в том, что мы полностью сократили проверку индекса массива ..

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

14 голосов
/ 21 марта 2011

Хороший пример - манипуляции с изображениями. Модификация пикселей с помощью указателя на их байты (что требует небезопасного кода) происходит немного быстрее.

Пример: http://www.gutgames.com/post/Using-Unsafe-Code-for-Faster-Image-Manipulation.aspx

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

1 голос
/ 29 сентября 2012

Ну, я бы посоветовал прочитать этот пост в блоге: Блоги MSDN: исключение проверки границ массива в CLR

Это разъясняет, как проверки границ выполняются в C #. Более того, тесты Томаса Братта кажутся мне бесполезными (глядя на код), так как JIT удаляет в своем 'save' циклы проверки в любом случае.

0 голосов
/ 05 февраля 2016

Я использую небезопасный код для манипулирования видео. В таком коде вы хотите, чтобы он работал как можно быстрее без внутренних проверок значений и т. Д. Без небезопасных атрибутов я не смог бы справиться с потоком видео со скоростью 30 кадров в секунду или 60 кадров в секунду. (в зависимости от используемой камеры).

Но из-за скорости он широко используется людьми, которые пишут графику.

...