Ada pendapat bahwa C # tidak memiliki tempat dalam tugas komputasi, dan pendapat ini cukup dibenarkan: kompiler JIT dipaksa untuk mengkompilasi dan mengoptimalkan kode dengan cepat selama eksekusi program dengan penundaan minimal, ia tidak memiliki kesempatan untuk menghabiskan lebih banyak sumber daya komputasi untuk menghasilkan kode yang lebih efisien , berbeda dengan compiler C ++, yang dapat memerlukan waktu beberapa menit bahkan berjam-jam untuk masalah ini.
Namun, dalam beberapa tahun terakhir, efisiensi compiler JIT telah meningkat secara nyata, dan sejumlah chip yang berguna telah dimasukkan ke dalam framework itu sendiri, misalnya, intrinsics .
Dan kemudian saya bertanya-tanya: apakah mungkin pada tahun 2020, menggunakan .NET 5.0, untuk menulis kode yang kinerjanya tidak akan jauh lebih rendah daripada C ++? Ternyata Anda bisa.
Motivasi
Saya terlibat dalam pengembangan algoritme pemrosesan gambar, dan pada level yang cukup rendah. Artinya, ini tidak menyulap batu bata dengan Python, tetapi mengembangkan sesuatu yang baru dan, lebih disukai, produktif. Kode Python membutuhkan waktu yang sangat lama, sementara menggunakan C ++ menyebabkan penurunan kecepatan pengembangan. Keseimbangan optimal antara produktivitas dan kinerja untuk tugas-tugas semacam itu dicapai dengan menggunakan C # dan Java. Sebagai konfirmasi atas kata-kata saya - proyek Fiji .
Sebelumnya, saya menggunakan C # untuk pembuatan prototipe, dan saya menulis ulang algoritme siap pakai yang sangat penting untuk kinerja di C ++, memasukkannya ke dalam lib dan menarik lib dari C #. Tetapi dalam kasus ini, portabilitas menderita, dan sangat tidak nyaman untuk men-debug kode.
, .NET , , C++ C#?
: , , , . C++. .
, , C# C++:
GetPixel(x, y) SetPixel(x, y, value);
;
(AVX).
(Array.Sort, std::sort), , , , . .
, , C# unmanaged - . - , C++ UB , C# - .
Github, , C#:
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public static void Sum_ThisProperty(NativeImage<float> img1, NativeImage<float> img2, NativeImage<float> res)
{
for (var j = 0; j < res.Height; j++)
for (var i = 0; i < res.Width; i++)
res[i, j] = img1[i, j] + img2[i, j];
}
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public static void Sum_Optimized(NativeImage<float> img1, NativeImage<float> img2, NativeImage<float> res)
{
var w = res.Width;
for (var j = 0; j < res.Height; j++)
{
var p1 = img1.PixelAddr(0, j);
var p2 = img2.PixelAddr(0, j);
var r = res.PixelAddr(0, j);
for (var i = 0; i < w; i++)
r[i] = p1[i] + p2[i];
}
}
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public static void Sum_Avx(NativeImage<float> img1, NativeImage<float> img2, NativeImage<float> res)
{
var w8 = res.Width / 8 * 8;
for (var j = 0; j < res.Height; j++)
{
var p1 = img1.PixelAddr(0, j);
var p2 = img2.PixelAddr(0, j);
var r = res.PixelAddr(0, j);
for (var i = 0; i < w8; i += 8)
{
Avx.StoreAligned(r, Avx.Add(Avx.LoadAlignedVector256(p1), Avx.LoadAlignedVector256(p2)));
p1 += 8;
p2 += 8;
r += 8;
}
for (var i = w8; i < res.Width; i++)
*r++ = *p1++ + *p2++;
}
}
. (1/10 ) 256x256 float 32 bit.
|
| dotnet build -c Release | g++ 10.2.0 -O0 | g++ 10.2.0 -O1 | g++ 10.2.0 -O2 | g++ 10.2.0 -O3 | clang 11.0.0 -O2 | clang 11.0.0 -O3 |
Sum (naive) | 115.8 | 757.6 | 124.4 | 36.26 | 19.51 | 20.14 | 19.81 |
Sum (opt) | 40.69 | 255.6 | 36.07 | 24.48 | 19.60 | 20.11 | 19.81 |
Sum (avx) | 21.15 | 60.41 | 20.00 | 20.18 | 20.37 | 20.23 | 20.20 |
Rotate (naive) | 90.29 | 500.3 | 87.15 | 36.01 | 14.49 | 14.04 | 14.16 |
Rotate (opt) | 34.99 | 237.1 | 35.11 | 34.17 | 14.55 | 14.10 | 14.27 |
Rotate (avx) | 14.83 | 51.04 | 14.14 | 14.25 | 14.37 | 14.22 | 14.72 |
Median 3x3 | 4163 | 26660 | 2930 | 1607 | 2508 | 2301 | 2330 |
Median 5x5 | 11550 | 10090 | 8240 | 5554 | 5870 | 5610 | 6051 |
Median 7x7 | 23540 | 24470 | 17540 | 13640 | 12620 | 12920 | 13510 |
Convolve 7x7 (naive) | 5519 | 30900 | 3240 | 3694 | 2775 | 3047 | 2761 |
Convolve 7x7 (opt) | 2913 | 11780 | 2759 | 2628 | 2754 | 2434 | 2262 |
Convolve 7x7 (avx) | 709.2 | 3759 | 729.8 | 669.8 | 684.2 | 643.8 | 638.3 |
Convolve 7x7 (avx*) | 505.6 | 2984 | 523.4 | 511.5 | 507.8 | 443.2 | 443.3 |
: Convolve 7x7 (avx*) - , , .
Core i7-2600K @ 4.0 GHz.
:
(avx), C#, , C++. , C# !
C# , C# , C++ .
C# C++ 2 6 . .
, C# , C++. : , C++ , C# . C#, C++.
P.S. .NET - - . (, ), C++ , , , C# , .