Yazılım Geliştirme: C ++ 17'de tahsisatçılarla optimizasyon
Polimorfik, C ++ 17'de tahsis eder, hafızanın hem performans hem de belleğin yeniden kullanılması üzerine atanmasını optimize etmeye yardımcı olur.
Rainer Grimm yıllardır yazılım mimarı, ekip ve eğitim müdürü olarak çalıştı. C ++ programlama dilleri, Python ve Haskell hakkında makaleler yazmayı seviyor, ancak uzman konferanslarla konuşmayı da seviyor. Modern C ++ blogunda, C ++ tutkusuyla yoğun bir şekilde ilgileniyor.
performans
Aşağıdaki program cppreference.com/monotonic_buffer_resource adresinden geliyor. Klan performansı ve MSVC derleyicisi için performansını genişleteceğim ve açıklayacağım.
// pmrPerformance.cpp
// https://en.cppreference.com/w/cpp/memory/monotonic_buffer_resource
#include <array>
#include <chrono>
#include <cstddef>
#include <iomanip>
#include <iostream>
#include <list>
#include <memory_resource>
template<typename Func>
auto benchmark(Func test_func, int iterations) // (1)
{
const auto start = std::chrono::system_clock::now();
while (iterations-- > 0)
test_func();
const auto stop = std::chrono::system_clock::now();
const auto secs = std::chrono::duration<double>(stop - start);
return secs.count();
}
int main()
{
constexpr int iterations{100};
constexpr int total_nodes{2'00'000};
auto default_std_alloc = [total_nodes] // (2)
{
std::list<int> list;
for (int i{}; i != total_nodes; ++i)
list.push_back(i);
};
auto default_pmr_alloc = [total_nodes] // (3)
{
std:
mr::list<int> list;
for (int i{}; i != total_nodes; ++i)
list.push_back(i);
};
auto pmr_alloc_no_buf = [total_nodes] // (4)
{
std:
mr::monotonic_buffer_resource mbr;
std:
mr:
olymorphic_allocator<int> pa{&mbr};
std:
mr::list<int> list{pa};
for (int i{}; i != total_nodes; ++i)
list.push_back(i);
};
auto pmr_alloc_and_buf = [total_nodes] // (5)
{
// enough to fit in all nodes:
std::array<std::byte, total_nodes * 32> buffer;
std:
mr::monotonic_buffer_resource mbr{buffer.data(),
buffer.size()};
std:
mr:
olymorphic_allocator<int> pa{&mbr};
std:
mr::list<int> list{pa};
for (int i{}; i != total_nodes; ++i)
list.push_back(i);
};
const double t1 = benchmark(default_std_alloc, iterations);
const double t2 = benchmark(default_pmr_alloc, iterations);
const double t3 = benchmark(pmr_alloc_no_buf , iterations);
const double t4 = benchmark(pmr_alloc_and_buf, iterations);
std::cout << std::fixed << std::setprecision(3)
<< "t1 (default std alloc): " << t1
<< " sec; t1/t1: " << t1/t1 << 'n'
<< "t2 (default pmr alloc): " << t2
<< " sec; t1/t2: " << t1/t2 << 'n'
<< "t3 (pmr alloc no buf): " << t3
<< " sec; t1/t3: " << t1/t3 << 'n'
<< "t4 (pmr alloc and buf): " << t4
<< " sec; t1/t4: " << t1/t4 << 'n';
}
(1) 'deki bu performans testi, (2) – (5)' deki işlevleri yüz kez yönlendirir (constexpr int iterations{100}). Her işlev çağrısı bir tane yaratır std:
mr::list<int> İki yüz bin düğüm ile (constexpr int total_nodes{2'00'000}). Bireysel listelerin düğümleri farklı şekillerde atanır:
İşte sayılar. Referans değeri, std::list<int> (Riga 2). Mutlak, ancak göreceli sayıları karşılaştırın, çünkü sanallaştırılmış bir Linux PC ve virtual olmayan bir Windows PC kullandım. Açıkçası maksimum optimizasyonu etkinleştirdim. Bu şu anlama gelir (/Ox) MSVC derleyicisi için ve (-Ox) GCC ve Clang derleyicisi için.
Depolama kaynağı ile bellek atamasının std:
mr::new_delete_resource En yavaş. Aksine std:
mr::monotonic_buffer Hafızanın en hızlı atanması. Bu, daha önce yığın üzerine atanmış bir arabellek kullanırsanız doğrudur. Windows'a bellek tahsisi yaklaşık on kat daha hızlıdır.
C ++ 20 ile tanıtılan kavramlar, modern C ++ uygulamalarının oluşturulmasını kütüphane, modüller ve aralıkların aralıkları ile yeniden tanımladı. 7 – 9 Kasım arasında 2023'te Rainer Grimm sizi yoğun C ++ 20 laboratuvarına getirdi: Yeni kavramlar tamamen açıkladı ve C ++ 20 Porta'nın birçok yararlı işlevine yanıt verdi.
Depolama kaynağı std:
mr::new_delete_resource Daha da fazla optimizasyon sunar.
Hafızanın yeniden kullanılması
std:
mr::monotonic_buffer Depolama sürümünü kaydedebilmeniz için belleğin yeniden kullanılmasını sağlar.
// reuseMemory.cpp
#include <array>
#include <cstddef>
#include <iostream>
#include <memory_resource>
#include <string>
#include <vector>
int main() {
std::array<std::byte, 2000> buf;
for (int i = 0; i < 100; ++i) { // (1)
std:
mr::monotonic_buffer_resource pool{buf.data(),
buf.size(), // (2)
std:
mr::null_memory_resource()};
std:
mr::vector<std:
mr::string> myVec{&pool};
for (int j = 0; j < 16; ++j) { // (3)
myVec.emplace_back("A short string");
}
}
}
Bu Alca Programı std::array 2000 bayt ile: std::array<std::byte, 2000>. Yığın tarafından atanan bu bellek yüz kez yeniden kullanılır (1). . std:
mr::vector<std:
rm::string> Kullanın std:
mr::monotonic_buffer_resource Yukarı akış depolama kaynağı ile std:
mr::null_memory_resource (2). Son olarak, taşıyıcıya 16 ip itilir.
Sırada ne var?
Bu makale C ++ 17'deki polimorfik depolama kaynakları hakkındaki mini serimi sona erdiriyor. Bir sonraki makalemde üç yıl boyunca atlamaya devam edeceğim ve C ++ 20 üzerinden yolculuğuma devam edeceğim.
(RME)
Yazılım Geliştirme: C ++ 17'de tahsisatçılarla optimizasyon
Polimorfik, C ++ 17'de tahsis eder, hafızanın hem performans hem de belleğin yeniden kullanılması üzerine atanmasını optimize etmeye yardımcı olur.

Rainer Grimm yıllardır yazılım mimarı, ekip ve eğitim müdürü olarak çalıştı. C ++ programlama dilleri, Python ve Haskell hakkında makaleler yazmayı seviyor, ancak uzman konferanslarla konuşmayı da seviyor. Modern C ++ blogunda, C ++ tutkusuyla yoğun bir şekilde ilgileniyor.
performans
Aşağıdaki program cppreference.com/monotonic_buffer_resource adresinden geliyor. Klan performansı ve MSVC derleyicisi için performansını genişleteceğim ve açıklayacağım.
// pmrPerformance.cpp
// https://en.cppreference.com/w/cpp/memory/monotonic_buffer_resource
#include <array>
#include <chrono>
#include <cstddef>
#include <iomanip>
#include <iostream>
#include <list>
#include <memory_resource>
template<typename Func>
auto benchmark(Func test_func, int iterations) // (1)
{
const auto start = std::chrono::system_clock::now();
while (iterations-- > 0)
test_func();
const auto stop = std::chrono::system_clock::now();
const auto secs = std::chrono::duration<double>(stop - start);
return secs.count();
}
int main()
{
constexpr int iterations{100};
constexpr int total_nodes{2'00'000};
auto default_std_alloc = [total_nodes] // (2)
{
std::list<int> list;
for (int i{}; i != total_nodes; ++i)
list.push_back(i);
};
auto default_pmr_alloc = [total_nodes] // (3)
{
std:
for (int i{}; i != total_nodes; ++i)
list.push_back(i);
};
auto pmr_alloc_no_buf = [total_nodes] // (4)
{
std:
std:
std:
for (int i{}; i != total_nodes; ++i)
list.push_back(i);
};
auto pmr_alloc_and_buf = [total_nodes] // (5)
{
// enough to fit in all nodes:
std::array<std::byte, total_nodes * 32> buffer;
std:
buffer.size()};
std:
std:
for (int i{}; i != total_nodes; ++i)
list.push_back(i);
};
const double t1 = benchmark(default_std_alloc, iterations);
const double t2 = benchmark(default_pmr_alloc, iterations);
const double t3 = benchmark(pmr_alloc_no_buf , iterations);
const double t4 = benchmark(pmr_alloc_and_buf, iterations);
std::cout << std::fixed << std::setprecision(3)
<< "t1 (default std alloc): " << t1
<< " sec; t1/t1: " << t1/t1 << 'n'
<< "t2 (default pmr alloc): " << t2
<< " sec; t1/t2: " << t1/t2 << 'n'
<< "t3 (pmr alloc no buf): " << t3
<< " sec; t1/t3: " << t1/t3 << 'n'
<< "t4 (pmr alloc and buf): " << t4
<< " sec; t1/t4: " << t1/t4 << 'n';
}
(1) 'deki bu performans testi, (2) – (5)' deki işlevleri yüz kez yönlendirir (constexpr int iterations{100}). Her işlev çağrısı bir tane yaratır std:
- (2): std::list<int> Küresel kullanma operator new
- (3): std:
mr::list<int> Özel Depolama Kaynağını Kullanın std:
mr::new_delete_resource
- (4): std:
mr::list<int> kullanılmış std:
mr::monotonic_buffer Daha önce yığın üzerine atanmış bir arabellek olmadan
- (5): std:
mr::list kullanılmış std:
mr::monotonic_buffer Daha önce yığın üzerine atanmış bir arabellek ile

İşte sayılar. Referans değeri, std::list<int> (Riga 2). Mutlak, ancak göreceli sayıları karşılaştırın, çünkü sanallaştırılmış bir Linux PC ve virtual olmayan bir Windows PC kullandım. Açıkçası maksimum optimizasyonu etkinleştirdim. Bu şu anlama gelir (/Ox) MSVC derleyicisi için ve (-Ox) GCC ve Clang derleyicisi için.



Depolama kaynağı ile bellek atamasının std:

C ++ 20 ile tanıtılan kavramlar, modern C ++ uygulamalarının oluşturulmasını kütüphane, modüller ve aralıkların aralıkları ile yeniden tanımladı. 7 – 9 Kasım arasında 2023'te Rainer Grimm sizi yoğun C ++ 20 laboratuvarına getirdi: Yeni kavramlar tamamen açıkladı ve C ++ 20 Porta'nın birçok yararlı işlevine yanıt verdi.
Depolama kaynağı std:
Hafızanın yeniden kullanılması
std:
// reuseMemory.cpp
#include <array>
#include <cstddef>
#include <iostream>
#include <memory_resource>
#include <string>
#include <vector>
int main() {
std::array<std::byte, 2000> buf;
for (int i = 0; i < 100; ++i) { // (1)
std:
buf.size(), // (2)
std:
std:
for (int j = 0; j < 16; ++j) { // (3)
myVec.emplace_back("A short string");
}
}
}
Bu Alca Programı std::array 2000 bayt ile: std::array<std::byte, 2000>. Yığın tarafından atanan bu bellek yüz kez yeniden kullanılır (1). . std:
Sırada ne var?
Bu makale C ++ 17'deki polimorfik depolama kaynakları hakkındaki mini serimi sona erdiriyor. Bir sonraki makalemde üç yıl boyunca atlamaya devam edeceğim ve C ++ 20 üzerinden yolculuğuma devam edeceğim.
(RME)