В общем, погонял в ленсуке:
$ dotnet --version
6.0.301
$ g++ --version
g++ (Ubuntu 11.2.0-19ubuntu1) 11.2.0
| C# |
| using System.Diagnostics;
var vals = new string[0x4000_000];
var random = new Random(DateTime.Now.Second);
var watch = Stopwatch.StartNew();
for (var i = 0; i < vals.Length; i++)
vals[i] = random.Next().ToString();
watch.Stop();
Console.WriteLine($"Init: {watch.Elapsed.TotalSeconds}");
TestPerformanceManaged(vals);
static void TestPerformanceManaged(string[] vals)
{
var watch = Stopwatch.StartNew();
var res = 0;
foreach (var val in vals)
res ^= ParseInt(val);
Console.WriteLine("Hash = {0:X}", res);
watch.Stop();
Console.WriteLine($"TestPerformanceManaged: {watch.Elapsed.TotalSeconds}");
}
static int ParseInt(string val)
{
int res = 0;
foreach (var d in val)
{
if ('0' <= d && d <= '9')
res = res * 10 + d - '0';
else
throw new ArgumentOutOfRangeException("'" + d + "': Symbol is out of the range");
}
return res;
}
|
| |
| C++ |
| #include <iostream>
#include <vector>
#include <string>
#include <chrono>
#include <random>
std::vector<std::wstring> MakeIntSequence(int size)
{
std::mt19937 gen(std::random_device{}());
std::uniform_int_distribution<> distrib(0, std::numeric_limits<int>::max());
std::vector<std::wstring> v;
v.reserve(size);
for (int i = 0; i < size; ++i)
v.push_back(std::to_wstring(distrib(gen)));
return v;
}
int ParseInt(const std::wstring& wstr)
{
int res{};
for (auto d : wstr)
{
if ('0' <= d && d <= '9')
res = res * 10 + d - '0';
else
throw std::out_of_range("'" + std::to_string(d) + "': Symbol is out of range");
}
return res;
}
int main()
{
namespace tm = std::chrono;
const auto vals = MakeIntSequence(0x4000000);
const auto t0 = tm::steady_clock::now();
int hash{};
for (const auto& val : vals)
hash ^= ParseInt(val);
const auto dt = tm::duration_cast<tm::milliseconds>(tm::steady_clock::now() - t0);
std::cout << "Hash = " << std::hex << hash << std::endl;
std::cout << "Processing time: " << std::dec << dt.count() << "ms" << std::endl;
}
|
| |
Флаги g++: `-std=c++17 -O2`. Флаги C# — ХЗ, запускал так: `dotnet run --configuration Release`.
Цепепе: 698, 704 и 715ms.
Сисярп: 0.7095647, 0.729915 и 0.7312779
std::string: ~690-695ms.
UPD
| u16string |
| #include <chrono>
#include <codecvt>
#include <iostream>
#include <locale>
#include <random>
#include <string>
#include <vector>
std::u16string to_u16string(int i)
{
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> conv;
return conv.from_bytes(std::to_string(i));
}
std::vector<std::u16string> MakeIntSequence(int size)
{
std::mt19937 gen(std::random_device{}());
std::uniform_int_distribution<> distrib(0, std::numeric_limits<int>::max());
std::vector<std::u16string> v;
v.reserve(size);
for (int i = 0; i < size; ++i)
v.push_back(to_u16string(distrib(gen)));
return v;
}
int ParseInt(const std::u16string& wstr)
{
int res{};
for (auto d : wstr)
{
if ('0' <= d && d <= '9')
res = res * 10 + d - '0';
else
throw std::out_of_range("'" + std::to_string(d) + "': Symbol is out of range");
}
return res;
}
int main()
{
namespace tm = std::chrono;
const auto vals = MakeIntSequence(0x4000000);
const auto t0 = tm::steady_clock::now();
int hash{};
for (const auto& val : vals)
hash ^= ParseInt(val);
const auto dt = tm::duration_cast<tm::milliseconds>(tm::steady_clock::now() - t0);
std::cout << "Hash = " << std::hex << hash << std::endl;
std::cout << "Processing time: " << std::dec << dt.count() << "ms" << std::endl;
}
|
| |
763, 772, 775ms и жрёт кучу памяти, больше, чем с 4-хбайтовым wstring. Думаю, из-за конверсий.