使用不安全与安全C#代码的优势是什么?
VS使用不安全与安全C#代码的优势是什么?,c#,unsafe,C#,Unsafe,VS 安全代码可以在任何情况下运行(Silverlight、共享托管ASP.NET、XNA、SQL Server等),而不安全代码需要更高的信任度。这意味着您可以在更多的地方和更少的限制下运行代码 此外,它是安全的,这意味着您不必担心出错和进程崩溃。我认为在您给出的示例中使用不安全代码没有好处。我只在需要与非托管代码交互时才真正使用过不安全代码,例如在调用非com dll接口时。使用不安全代码的原因只有一个:原始性能 使用不安全代码,可以使用类似C++的指针,而不用太多的运行时间检查。没有支票意
安全代码可以在任何情况下运行(Silverlight、共享托管ASP.NET、XNA、SQL Server等),而不安全代码需要更高的信任度。这意味着您可以在更多的地方和更少的限制下运行代码
此外,它是安全的,这意味着您不必担心出错和进程崩溃。我认为在您给出的示例中使用不安全代码没有好处。我只在需要与非托管代码交互时才真正使用过不安全代码,例如在调用非com dll接口时。使用不安全代码的原因只有一个:原始性能
使用不安全代码,可以使用类似C++的指针,而不用太多的运行时间检查。没有支票意味着你只能靠自己,但开销会少一些
我只看到它在加速图像/位图操作方面发挥了作用。但您也可以将其用于内联字符串操作(是的,使字符串可变!!!除非您想构建StringBuilder,否则这是个坏主意)。其他用途包括矩阵计算或其他繁重的数学运算。可能是与操作系统的接口,以及一些黑客行为。您的示例并不好,JIT编译器已经生成了这样的代码。引擎盖下的引用也是指针。这需要很快,托管代码永远不会有竞争力 垃圾收集堆与指针非常不兼容,必须固定对象才能创建指向它们的指针。如果没有固定,垃圾收集器可能会移动对象,并且代码会随机失败,从而破坏堆的完整性。固定具有非零成本,无论是在操作中还是在取消固定之后,当对象被固定时发生垃圾收集时,您都将遭受效率损失
指针在访问非托管内存时非常有效。典型的例子是需要访问位图像素的图像处理。这是一种在移除所有安全联锁的情况下快速访问固定阵列的方法,当您不迭代它们时,阵列索引检查不是免费的。一个完美的例子在J.Richter《CLR通过C#》一书第3版第16章中描述: 下面的C#代码演示了访问二维数组的三种技术(安全、锯齿和不安全):
static void SquarePtrParam (ref int p)
{
p *= p;
}
如您所见,安全的二维阵列访问技术是最慢的。安全锯齿阵列访问技术比安全二维阵列访问技术所需的时间要短一些。但是,您应该注意,创建交错数组比创建多维数组更耗时,因为创建交错数组需要在堆上为每个维度分配一个对象,从而导致垃圾收集器周期性地启动。因此有一个折衷办法:如果需要创建大量“多维数组”,并且希望不经常访问元素,那么创建多维数组会更快。如果只需要创建一次“多维数组”,并且经常访问其元素,则锯齿数组将提供更好的性能。当然,在大多数应用程序中,后一种情况更常见。@forsvarir:在这种情况下使用不安全代码没有任何好处,所以我告诉他使用安全代码的好处。
担心做错事会破坏进程。
有点误导性的说法-执行无限for循环,它会崩溃。Safe并不是100%防错的。通常互操作(COM或P/Invoke)不需要不安全的代码。你几乎总是可以使用ref
或out
来代替指针。我认为只要没有垃圾收集,固定的成本是零的,不是吗?@Mehrdad-创建GCHandle不是免费的。固定一个对象肯定会有一些成本,否则它将是一个NOP。问题是成本是多少。BCL在类中广泛使用String
和BitConverter
中的fixed
指针,因此我认为成本不会太高。现在想想看,fixed
部分可能只是GC使用的元数据。抖动可以存储代码中某个点的某个寄存器中的值指向无法重新定位的对象的信息。因此,使用fixed
可能会为GC增加额外的元数据开销和额外的工作,但不会在执行时消耗CPU周期。它创建另一个对垃圾收集器可见的指针。非常有效。@Timeless:。@Mehrdad谢谢<代码>“与底层操作系统接口、访问内存映射设备或实现时间关键算法”等
static void SquarePtrParam (ref int p)
{
p *= p;
}
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;
}
}
00:00:02.0017692: Safe2DimArrayAccess
00:00:01.5197844: SafeJaggedArrayAccess
00:00:01.7343436: Unsafe2DimArrayAccess