В чем преимущество использования небезопасного и безопасного кода C #? - PullRequest
8 голосов
/ 23 марта 2011
unsafe static void SquarePtrParam (int* p) 
   {
      *p *= *p;
   }

VS

static void SquarePtrParam (ref int p) 
   {
      p *= p;
   }

Ответы [ 5 ]

11 голосов
/ 23 марта 2011

Безопасный код может выполняться в любой ситуации, когда вы можете запустить код C # (Silverlight, общий хостинг ASP.NET, XNA, SQL Server и т. Д.), Тогда как небезопасный код требует повышенного доверия. Это означает, что вы можете запускать свой код в большем количестве мест и с меньшими ограничениями.

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

9 голосов
/ 23 марта 2011

Ваш пример не очень хороший, JIT-компилятор уже генерирует такой код. Под капотом ссылки тоже есть указатели. Это должно было быть быстро, управляемый код никогда не был бы конкурентоспособным.

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

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

7 голосов
/ 23 марта 2011

Существует только одна причина для использования небезопасного кода: необработанная производительность.

Используя небезопасный код, вы можете использовать C ++, как указатели, без особой проверки во время выполнения.Отсутствие проверок означает, что вы сами по себе, но накладных расходов меньше.

Я видел это только в действии для ускорения работы с изображениями / растровыми изображениями.Но вы также можете использовать его для работы со встроенными строками (да, делать строки изменяемыми !!! Плохая идея в любом случае, если вы не хотите собирать StringBuilder).Другие применения включают матричные вычисления или другую тяжелую математику.И, вероятно, взаимодействие с ОС, и некоторые взломы.

2 голосов
/ 17 февраля 2012

Прекрасный пример описан в книге Дж. Рихтера "CLR via C #", 3 издание, гл. 16: Следующий код C # демонстрирует три метода (безопасный, зубчатый и небезопасный) для доступа к двумерному массиву:

using System;
using System.Diagnostics;

public static class Program {
    private const Int32 c_numElements = 10000;

    public static void Main() {
        const Int32 testCount = 10;
        Stopwatch sw;

        // Declare a two-dimensional array
        Int32[,] a2Dim = new Int32[c_numElements, c_numElements];
        // Declare a two-dimensional array as a jagged array (a vector of vectors)
        Int32[][] aJagged = new Int32[c_numElements][];
        for (Int32 x = 0; x < c_numElements; x++)
            aJagged[x] = new Int32[c_numElements];

        // 1: Access all elements of the array using the usual, safe technique
        sw = Stopwatch.StartNew();
        for (Int32 test = 0; test < testCount; test++)
            Safe2DimArrayAccess(a2Dim);
        Console.WriteLine("{0}: Safe2DimArrayAccess", sw.Elapsed);

        // 2: Access all elements of the array using the jagged array technique
        sw = Stopwatch.StartNew();
        for (Int32 test = 0; test < testCount; test++)
            SafeJaggedArrayAccess(aJagged);
        Console.WriteLine("{0}: SafeJaggedArrayAccess", sw.Elapsed);

        // 3: Access all elements of the array using the unsafe technique
        sw = Stopwatch.StartNew();
        for (Int32 test = 0; test < testCount; test++)
            Unsafe2DimArrayAccess(a2Dim);
        Console.WriteLine("{0}: Unsafe2DimArrayAccess", sw.Elapsed);
        Console.ReadLine();
    }

    private static Int32 Safe2DimArrayAccess(Int32[,] a) {
        Int32 sum = 0;
        for (Int32 x = 0; x < c_numElements; x++) {
            for (Int32 y = 0; y < c_numElements; y++) {
                sum += a[x, y];
            }
        }

        return sum;
    }

    private static Int32 SafeJaggedArrayAccess(Int32[][] a) {
        Int32 sum = 0;
        for (Int32 x = 0; x < c_numElements; x++) {
            for (Int32 y = 0; y < c_numElements; y++) {
                sum += a[x][y];
            }
        }

        return sum;
    }

    private static unsafe Int32 Unsafe2DimArrayAccess(Int32[,] a) {
        Int32 sum = 0;
        fixed (Int32* pi = a) {
            for (Int32 x = 0; x < c_numElements; x++) {
                Int32 baseOfDim = x * c_numElements;
                for (Int32 y = 0; y < c_numElements; y++) {
                    sum += pi[baseOfDim + y];
                }
            }
        }

        return sum;
    }
}

Метод Unsafe2DimArrayAccess помечается модификатором unsafe, который требуется использовать фиксированное утверждение C #. Чтобы скомпилировать этот код, вам потребуется указать параметр / unsafe при вызове компилятора C # или установить флажок «Разрешить небезопасный код» на вкладке «Построение» панели «Свойства проекта» в Microsoft Visual Studio. Когда я запускаю эту программу на своем компьютере, я получаю следующий вывод:

00:00:02.0017692: Safe2DimArrayAccess
00:00:01.5197844: SafeJaggedArrayAccess
00:00:01.7343436: Unsafe2DimArrayAccess

Как видите, безопасный метод доступа к двумерным массивам самый медленный. Техника безопасного доступа к зазубренным массивам занимает немного меньше времени, чем безопасная техника доступа к двумерным массивам. Однако следует отметить, что создание зубчатого массива занимает больше времени, чем создание многомерного массива, поскольку создание зубчатого массива требует размещения объекта в куче для каждого измерения, что приводит к периодическому запуску сборщика мусора. Таким образом, существует компромисс: если вам нужно создать много «многомерных массивов» и вы намерены обращаться к элементам нечасто, быстрее создать многомерный массив. Если вам нужно создать «многомерный массив» только один раз, и вы часто обращаетесь к его элементам, зубчатый массив даст вам лучшую производительность. Конечно, в большинстве приложений последний сценарий более распространен.

1 голос
/ 23 марта 2011

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

...