OK đây là bộ phận thử nghiệm của tôi. Thuộc tính dự án của tôi là Release Build, "tối ưu hóa mã" và cũng "Cho phép mã không an toàn" được chọn.
Đáng ngạc nhiên (với tôi dù sao) hiệu suất là rất khác nhau bên trong và bên ngoài IDE. Khi chạy từ IDE có sự khác biệt đáng chú ý (và sự khác biệt x64 là rất lớn). Khi chạy bên ngoài IDE, đó là một rửa.
Vì vậy, điều này thật lạ và tôi không thể giải thích kết quả cho IDE + x64. Có lẽ điều này là thú vị đối với một số người, nhưng bởi vì nó không còn là mục đích cung cấp câu trả lời cho câu hỏi ban đầu của người đăng, có lẽ điều này nên được chuyển sang một chủ đề khác không?
Bên trong IDE, nền tảng thiết lập để x86
pass 1: old 00:00:09.7505625 new 00:00:08.6897013 percent 0.1088
Bên trong IDE, nền tảng thiết lập để x64
pass 1: old 00:00:14.7584514 new 00:00:08.8835715 percent 0.398068858362741
Chạy từ dòng lệnh, nền tảng thiết lập để x86
pass 1: old 00:00:07.6576469 new 00:00:07.2818252 percent 0.0490779615341104
Chạy từ dòng lệnh, nền tảng được đặt thành x64
pass 1: old 00:00:07.2501032 new 00:00:07.3077479 percent -0.00795087992678504
Và đây là đoạn code:
using System;
using System.Runtime.InteropServices;
namespace ConsoleApplication23 {
public class Program {
public static void Main() {
const int repeatCount=20;
const int arraySize=5000000;
var values=MakeValues(arraySize);
for(var pass=0; pass<2; ++pass) {
Console.WriteLine("Starting old");
var startOld=DateTime.Now;
for(var i=0; i<repeatCount; ++i) {
var result=TransformOld(values);
}
var elapsedOld=DateTime.Now-startOld;
Console.WriteLine("Starting new");
var startNew=DateTime.Now;
for(var i=0; i<repeatCount; ++i) {
var result=TransformNew(values);
}
var elapsedNew=DateTime.Now-startNew;
var difference=elapsedOld-elapsedNew;
var percentage=(double)difference.TotalMilliseconds/elapsedOld.TotalMilliseconds;
Console.WriteLine("pass {0}: old {1} new {2} percent {3}", pass, elapsedOld, elapsedNew, percentage);
}
Console.Write("Press enter: ");
Console.ReadLine();
}
private static float4x4[] MakeValues(int count) {
var result=new float4x4[count];
for(var i=0; i<count; ++i) {
result[i]=new float4x4(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
}
return result;
}
public static float[] TransformOld(float4x4[] value) {
var array=new float[value.Length*16];
int n = 0;
for(int i = 0; i < value.Length; i++) {
array[n++] = value[i].M11;
array[n++] = value[i].M12;
array[n++] = value[i].M13;
array[n++] = value[i].M14;
array[n++] = value[i].M21;
array[n++] = value[i].M22;
array[n++] = value[i].M23;
array[n++] = value[i].M24;
array[n++] = value[i].M31;
array[n++] = value[i].M32;
array[n++] = value[i].M33;
array[n++] = value[i].M34;
array[n++] = value[i].M41;
array[n++] = value[i].M42;
array[n++] = value[i].M43;
array[n++] = value[i].M44;
}
return array;
}
public static unsafe float[] TransformNew(float4x4[] values) {
var array=new float[values.Length*16];
fixed(float* arrayStart=array) {
var destp=arrayStart;
fixed(float4x4* valuesStart=values) {
int count=values.Length;
for(var valuesp=valuesStart; count>0; ++valuesp, --count) {
var sourcep=valuesp->data;
for(var i=0; i<16/4; ++i) {
*destp++=*sourcep++;
*destp++=*sourcep++;
*destp++=*sourcep++;
*destp++=*sourcep++;
}
}
}
return array;
}
}
[StructLayout(LayoutKind.Explicit)]
public unsafe struct float4x4 {
[FieldOffset(0)] public float M11;
[FieldOffset(4)] public float M12;
[FieldOffset(8)] public float M13;
[FieldOffset(12)] public float M14;
[FieldOffset(16)] public float M21;
[FieldOffset(20)] public float M22;
[FieldOffset(24)] public float M23;
[FieldOffset(28)] public float M24;
[FieldOffset(32)] public float M31;
[FieldOffset(36)] public float M32;
[FieldOffset(40)] public float M33;
[FieldOffset(44)] public float M34;
[FieldOffset(48)] public float M41;
[FieldOffset(52)] public float M42;
[FieldOffset(56)] public float M43;
[FieldOffset(60)] public float M44;
//notice the use of "fixed" keyword to make the array inline
//and the use of the FieldOffset attribute to overlay that inline array on top of the other fields
[FieldOffset(0)] public fixed float data[16];
public float4x4(float m11, float m12, float m13, float m14,
float m21, float m22, float m23, float m24,
float m31, float m32, float m33, float m34,
float m41, float m42, float m43, float m44) {
M11=m11; M12=m12; M13=m13; M14=m14;
M21=m21; M22=m22; M23=m23; M24=m24;
M31=m31; M32=m32; M33=m33; M34=m34;
M41=m41; M42=m42; M43=m43; M44=m44;
}
}
}
}
Vâng, bạn có thể sử dụng mã không an toàn. Nếu bạn nhận được một con trỏ tới 'value [i]', bạn có thể sử dụng 'Marshal.Copy' để sao chép nó vào' mảng'. Cho dù đó là sạch hơn, tôi không chắc chắn .. – harold
Là một cấu trúc, đó là khá quá trọng lượng ... cấu trúc có kích thước hướng dẫn, FWIW –
nếu bạn sử dụng StructLayout với Explicit và xác định kích thước và bố cục thì bạn có thể sử dụng một lớp C++/CLI đơn giản để diễn giải lại một con trỏ được ghim vào mục nhập đầu tiên trong mảng và memcpy. Điều này có tất cả các loại báo trước nhưng rất nhanh. Tuy nhiên, tôi sẽ lập luận rằng, nếu bạn không có khả năng viết một điều như vậy cho mình, bạn có lẽ không nên làm điều đó cho đến khi bạn đã học được như thế nào. – ShuggyCoUk