Я понимаю, что небезопасный код больше подходит для доступа к таким вещам, как Windows API, и для небезопасного приведения типов, чем для написания более производительного кода, но я хотел бы спросить вас, замечали ли вы когда-нибудь значительное улучшение производительности в реальных приложениях с его использованием. по сравнению с безопасным кодом С#.
Истинно небезопасная производительность кода
Ответы (6)
Некоторые показатели эффективности
Преимущества в производительности не так велики, как вы думаете.
Я провел некоторые измерения производительности обычного доступа к управляемому массиву по сравнению с небезопасными указателями в 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
Обратите внимание, что идиома unsafe *(p++)
на самом деле работала медленнее. Я предполагаю, что это нарушило оптимизацию компилятора, которая объединяла переменную цикла и (сгенерированный компилятором) доступ к указателю в безопасной версии.
Исходный код доступен на github.
unsafe
и использование ptr++
не приводит к существенному выигрышу. Это ценная информация; Я ценю это. Чего не хватает, так это какого-либо понимания того, когда unsafe
может быть намного быстрее, или, наоборот, показать, что unsafe
не быстрее, в более существенных вычислениях. Однако это полезная отправная точка; благодаря.
- person ToolmakerSteve; 03.03.2018
Как было сказано в других сообщениях, вы можете использовать небезопасный код в очень специализированных контекстах, чтобы получить значительное повышение производительности. Один из таких сценариев — перебор массивов типов значений. Использование небезопасной арифметики указателя намного быстрее, чем использование обычного шаблона 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...
}
}
Основное преимущество здесь в том, что мы полностью убрали проверку индекса массива.
Несмотря на высокую производительность, с таким кодом сложно работать, он может быть довольно опасным (небезопасным) и нарушать некоторые основные правила (изменяемая структура). Но есть, конечно, сценарии, когда это уместно...
Хорошим примером являются манипуляции с изображениями. Изменение пикселей с помощью указателя на их байты (для чего требуется небезопасный код) происходит немного быстрее.
Пример: http://www.gutgames.com/post/Using-Unsafe-Code-for-Faster-Image-Manipulation.aspx
При этом для большинства сценариев разница не будет столь заметной. Поэтому, прежде чем использовать небезопасный код, профилируйте свое приложение, чтобы увидеть, где находятся узкие места в производительности, и проверьте, действительно ли небезопасный код является решением для его ускорения.
byte[]
, вы даже можете избежать этого и просто использовать функции Marshal
.
- person CodesInChaos; 21.03.2011
GetPixel
и SetPixel
работает очень медленно, но использование int[]
более или менее быстро, чем использование указателей без недостатков.
- person Thomas Bratt; 10.07.2012
Marshal
.
- person Thomas Bratt; 10.07.2012
Что ж, я бы посоветовал прочитать этот пост в блоге: Блоги MSDN: устранение проверки границ массива в среде CLR
Это поясняет, как выполняются проверки границ в C#. Более того, тесты Томаса Брэттса кажутся мне бесполезными (смотря на код), поскольку JIT все равно удаляет в своих циклах «сохранения» связанные проверки.
Я использую небезопасный код для обработки видео. В таком коде вы хотите, чтобы он работал как можно быстрее без внутренних проверок значений и т. Д. Без небезопасных атрибутов мой мог бы не справиться с видеопотоком со скоростью 30 кадров в секунду или 60 кадров в секунду. (в зависимости от используемой камеры).
Но из-за скорости он широко используется людьми, которые кодируют графику.
Всем, кто просматривает эти ответы, я хотел бы отметить, что, несмотря на то, что ответы превосходны, многое изменилось, потому что ответы были опубликованы.
Обратите внимание, что .net сильно изменился, и теперь у него также есть возможность доступа к новым типам данных, таким как векторы, Span, ReadOnlySpan, а также к специфичным для оборудования библиотекам и классам, таким как найденные в System.Runtime.Intrinsics в ядре 3.0
Взгляните на этот сообщение в блоге, чтобы узнать, как можно использовать оптимизированные циклы, и это блог о том, как вернуться к безопасным методам, если оптимальное оборудование недоступно.
unsafe
... Я не уверен, что это следует из рассуждений... Кроме того: вы измерили, не делаете ли вы здесь что-то полезное? - person Marc Gravell   schedule 21.03.2011unsafe
, убедитесь, что вы знаете, как эффективно использовать C#. Избегайте чрезмерного создания временных объектов. Когда использовать массив структур и на что следует обратить внимание.Buffer.BlockCopy
. Условия, при которых JIT оптимизирует проверку границ массива. (Я не эксперт, просто говорю то, что приходит на ум.) Google Высокая производительность C# и Советы по производительности C#. - person ToolmakerSteve   schedule 03.03.2018