C ++ Programlama Dili: C ++ 26'da Kapsayıcı Tarama Uzantısı
Kapsayıcı tarama, bir dizideki bir dizi öğenin toplamının hesaplanması gibi alan sorgularına ilişkin sorunları çözer. Ayrıca alanın minimum sorgusu ve diğer çeşitli algoritmalar için de kullanılır.
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.
Noel Özel
Farkı yaratmak
Birlikte olağanüstü bir şey yapalım: 1 Aralık'tan 24 Aralık'a kadar, ders programlarımdan birini rezerve ederseniz SLA ile ilgili araştırma için paranın yarısını bağışlayacağım.
Şimdiye kadar neler başardığımızı görebilmemiz için her hafta bir güncelleme yayınlayacağım.
Burada ders programlarımın ve bireysel programlarımın yapısı hakkında benim hakkımda daha fazla bilgi bulacaksınız:
Siz veya ekibiniz size mentorluk programımdan özel bir seçim diliyorsanız, lütfen [email protected] adresinden benimle iletişime geçin. Bir çözüm buluyoruz.
Neden?
İşte SLA'nın ASSLANCE Kliniğinin de bir beyanı:
“Tıp yetimlerinden” biri – sosyal olarak odaklanmayan nadir hastalıklar. Tedavi açıkça alt -çocukluktur ve SLA üzerinde araştırma için yeterli araç da yoktur. Bağışlar ve diğer üçüncü taraf fonları temel öneme sahiptir.
Bu alt -analyzing, buz kovasının zorluğu ile açıktı.
Araştırmanın daha fazla paraya ihtiyacı var.
Somma önek
Asinnano'daki eşzamansız taramaya girmeden önce, önek olarak da adlandırılan kapsayıcı taramayı tanıtmak istiyorum.
Aşağıdaki tanım İngilizce Wikipedia -lingua'da mevcuttur: “Bilgisayar Biliminde önek, kümülatif toplam, dahil edilen tarama veya sadece X sayısının bir dizisini tarama.0X1X2… y sayılarının ikinci bir dizisi0y1y2…, giriş sırasının öneklerinin (toplam yürütme) toplamları: “
y0 = x0
y1 = x0 + x1
y2 = x0 + x1+ x2
...
P2300R10 teklifi, kapsayıcı taramanın uygulanmasını sunar.
using namespace std::execution;
sender auto async_inclusive_scan(scheduler auto sch, // 2
std::span<const double> input, // 1
std::span<double> output, // 1
double init, // 1
std::size_t tile_count) // 3
{
std::size_t const tile_size = (input.size() + tile_count - 1) / tile_count;
std::vector<double> partials(tile_count + 1); // 4
partials[0] = init; // 4
return just(std::move(partials)) // 5
| continues_on(sch)
| bulk(tile_count, // 6
[ = ](std::size_t i, std::vector<double>& partials) { // 7
auto start = i * tile_size; // 8
auto end = std::min(input.size(), (i + 1) * tile_size); // 8
partials[i + 1] = *--std::inclusive_scan(begin(input) + start, // 9
begin(input) + end, // 9
begin(output) + start); // 9
}) // 10
| then( // 11
[](std::vector<double>&& partials) {
std::inclusive_scan(begin(partials), end(partials), // 12
begin(partials)); // 12
return std::move(partials); // 13
})
| bulk(tile_count, // 14
[ = ](std::size_t i, std::vector<double>& partials) { // 14
auto start = i * tile_size; // 14
auto end = std::min(input.size(), (i + 1) * tile_size); // 14
std::for_each(begin(output) + start, begin(output) + end, // 14
[&] (double& e) { e = partials + e; } // 14
);
})
| then( // 15
[ = ](std::vector<double>&& partials) { // 15
return output; // 15
}); // 15
}
İşte Almancaya çevrilen P2300R10 teklifinin açıklaması.
Hier hilft die Referenzimplementierung stdexec, wobei ich den Datentyp der verarbeiteten Elemente von double in int geändert habe:
// inclusiveScanExecution.cpp
#include <algorithm>
#include <exec/static_thread_pool.hpp>
#include <iostream>
#include <numeric>
#include <span>
#include <stdexec/execution.hpp>
#include <vector>
auto async_inclusive_scan(auto sch, // 2
std::span<const int> input, // 1
std::span<int> output, // 1
int init, // 1
std::size_t tile_count) // 3
{
std::size_t const tile_size = (input.size() + tile_count - 1) / tile_count;
std::vector<int> partials(tile_count + 1); // 4
partials[0] = İnit; // 4 STDEXEC :: Just (std :: move (kısmi)) // 5 | Stdexec :: continues_on (SCH) | Stdexec :: toplu (karo_count, // 6
[=](Std :: size_t i, std :: vektör & kısmi) {// 7 Arabalar Start = i * fayans_size; // 8 End Auto = std :: min (input.size (), (i + 1) * fayans_size); // 8 kısmi[i + 1] = *-STD :: Inclurment_scan (başlangıç (giriş) + başlangıç, // 9 başlangıç (giriş) + bitiş, // 9 start (çıktı) + start); // 9}) // 10 | Stdexec :: So (// 11
[](Std :: vektör kısmi &&) {std :: dahil Inclurment_scan (başlangıç (kısmi), son (kısmi), // 12 başlangıç (kısmi)); // 12 Dönüş std :: move (kısmi); // 13}) | Stdexec :: toplu (karo_count, // 14
[=](Std :: size_t i, std :: vektör & kısmi) {// 14 araba Start = i * fayans_size; // 14 End Auto = std :: min (input.size (), (i + 1) * fayans_size); // 14 saat :: for_each (başlangıç (çıktı) + başlat, başlat (çıktı) + bitiş, // 14
[&](int & e) {e = kısmi + E; } // 14); }) | Stdexec :: So (// 15
[=](Std :: vektör & & kısmi) {// 15 dönüş çıkışı; // 15}); // 15} int main () {std :: cout Giriş (30); Std :: IOTA (başlangıç (giriş), son (giriş), 0); (araba e: giriş) {std :: cout Çıktı (input.size ()); Exec :: Static_thread_pool Pool (8); Otomatik sch = pool.get_scaduler (); araba [out] = Stdexec :: sync_wait (async_inclusive_scan (Sch, giriş, çıktı, 0, 4)). Değer (); for (araba e: out) {std :: cout code>
İçinde main Olacak mı std::vector<int> Giriş 30 elementle oluşturuldu. . std::iota-Kunksiyonu doldurur input-Genercide iç sayıları olan vektör, 0. Bu nedenle program, konsoldaki taşıyıcının içeriğini yayınlar.
Diğerleri bir std::vector<int> output Aynı boyutta input-İfector kapsayıcı tarama ameliyatının sonuçlarını kurtarmak için oluşturuldu. . exec::static_thread_pool pool Görevlerin eşzamanlı olarak yürütülmesi için kullanılan iş parçacıklarına sahiptir. . get_scheduler-İplik havuzunun üyesinin işlevi bir zamanlayıcı nesne oluşturur sch.
İşlev async_inclusive_scan Zamanlayıcıyı kullanın schtaşıyıcı inputtaşıyıcı outputbaşlangıç değeri 0 ve bir dizi fayans 4. Bu işlev, belirtilen zamanlayıcı kullanarak eşzamansız kapsayıcı tarama ameliyatı gerçekleştirir ve bir geleceğe benzer bir nesne döndürür. İşlev stdexec::sync_wait Sonu için senkronize bekleyin async_inclusive_scan-Okalizasyon ve sonuç değişkendedir out Dağınık.
Son olarak, program taşıyıcının içeriğini sağlar out Konsolda:
Sırada ne var?
Bir sonraki blog yazımda, operatör aracılığıyla yayıncıların bir adım ve kompozisyonu yapacağım | açıklamak.
(RME)
C ++ Programlama Dili: C ++ 26'da Kapsayıcı Tarama Uzantısı
Kapsayıcı tarama, bir dizideki bir dizi öğenin toplamının hesaplanması gibi alan sorgularına ilişkin sorunları çözer. Ayrıca alanın minimum sorgusu ve diğer çeşitli algoritmalar için de kullanılır.

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.
Noel Özel
Farkı yaratmak

Birlikte olağanüstü bir şey yapalım: 1 Aralık'tan 24 Aralık'a kadar, ders programlarımdan birini rezerve ederseniz SLA ile ilgili araştırma için paranın yarısını bağışlayacağım.
Şimdiye kadar neler başardığımızı görebilmemiz için her hafta bir güncelleme yayınlayacağım.
Burada ders programlarımın ve bireysel programlarımın yapısı hakkında benim hakkımda daha fazla bilgi bulacaksınız:
Siz veya ekibiniz size mentorluk programımdan özel bir seçim diliyorsanız, lütfen [email protected] adresinden benimle iletişime geçin. Bir çözüm buluyoruz.
Neden?
İşte SLA'nın ASSLANCE Kliniğinin de bir beyanı:
“Tıp yetimlerinden” biri – sosyal olarak odaklanmayan nadir hastalıklar. Tedavi açıkça alt -çocukluktur ve SLA üzerinde araştırma için yeterli araç da yoktur. Bağışlar ve diğer üçüncü taraf fonları temel öneme sahiptir.
Bu alt -analyzing, buz kovasının zorluğu ile açıktı.
Araştırmanın daha fazla paraya ihtiyacı var.
Somma önek
Asinnano'daki eşzamansız taramaya girmeden önce, önek olarak da adlandırılan kapsayıcı taramayı tanıtmak istiyorum.
Aşağıdaki tanım İngilizce Wikipedia -lingua'da mevcuttur: “Bilgisayar Biliminde önek, kümülatif toplam, dahil edilen tarama veya sadece X sayısının bir dizisini tarama.0X1X2… y sayılarının ikinci bir dizisi0y1y2…, giriş sırasının öneklerinin (toplam yürütme) toplamları: “
y0 = x0
y1 = x0 + x1
y2 = x0 + x1+ x2
...
P2300R10 teklifi, kapsayıcı taramanın uygulanmasını sunar.
using namespace std::execution;
sender auto async_inclusive_scan(scheduler auto sch, // 2
std::span<const double> input, // 1
std::span<double> output, // 1
double init, // 1
std::size_t tile_count) // 3
{
std::size_t const tile_size = (input.size() + tile_count - 1) / tile_count;
std::vector<double> partials(tile_count + 1); // 4
partials[0] = init; // 4
return just(std::move(partials)) // 5
| continues_on(sch)
| bulk(tile_count, // 6
[ = ](std::size_t i, std::vector<double>& partials) { // 7
auto start = i * tile_size; // 8
auto end = std::min(input.size(), (i + 1) * tile_size); // 8
partials[i + 1] = *--std::inclusive_scan(begin(input) + start, // 9
begin(input) + end, // 9
begin(output) + start); // 9
}) // 10
| then( // 11
[](std::vector<double>&& partials) {
std::inclusive_scan(begin(partials), end(partials), // 12
begin(partials)); // 12
return std::move(partials); // 13
})
| bulk(tile_count, // 14
[ = ](std::size_t i, std::vector<double>& partials) { // 14
auto start = i * tile_size; // 14
auto end = std::min(input.size(), (i + 1) * tile_size); // 14
std::for_each(begin(output) + start, begin(output) + end, // 14
[&] (double& e) { e = partials + e; } // 14
);
})
| then( // 15
[ = ](std::vector<double>&& partials) { // 15
return output; // 15
}); // 15
}
İşte Almancaya çevrilen P2300R10 teklifinin açıklaması.
- İşlev bir dizi tarar doubleS (nasıl gösterildi std::span<const double> inputve sonucu farklı bir bölümde kaydedin doubleS (nasıl gösterildi std::span<double> output).
- Bir zamanlayıcı, taramanın hangi yürütme kaynağının başlatılması gerektiğini belirtmek için kullanılır.
- Ayrıca bir tile_count-Parametreler, üretilen ajan sayısını kontrol eden kullandı.
- Öncelikle, algoritma için gerekli olan geçici belleğe atamalıyız. std::vector, partials tamamlamak. Tarafımızdan oluşturulan her yürütme aracısı için çift geçici bir belleğe ihtiyacımız var.
- Daha sonra ilk ihraççımızı oluşturacağız execution::just VE execution::continues_on. Bu vericiler, vericiye taşındığımız geçici belleği gönderir. İhraççının bir tamamlama zamanlayıcısına sahiptir. schyani zincirdeki bir sonraki element sch kullanılmış.
- Vericinin ve verici adaptörü kompozisyonu destekler operator|C ++ alanlarına benzer. Kullanıyoruz operator |Bir sonraki çalışmaya saldırmak için tile_count-Kunking Farms kullanıyor execution::bulkS oluştu.
- Her ajan bir tane arar std::invocable Auf ve iki konu sun. Birincisi, ajanın endeksidir (i) execution::bulk-Okalizasyon, bu durumda net bir tamsayı [0, tile_count). Das zweite Argument ist, wie der Eingabesender gesendet hat – der temporäre Speicher.
- Wir beginnen mit der Berechnung von Anfang und Ende des Bereichs der Eingabe- und Ausgabeelemente, für die dieser Agent verantwortlich ist, basierend auf unserem Agentenindex.
- Dann führen wir einen sequenziellen std::inclusive_scan über unsere Elemente durch. Wir speichern das Scan-Ergebnis für unser letztes Element, das die Summe aller unserer Elemente ist, in unserem temporären Speicher “partials“.
- Nachdem alle Berechnungen in diesem ersten Durchlauf in großen Mengen abgeschlossen sind, hat jeder der erzeugten Ausführungsagenten die Summe seiner Elemente in seinen Slot in Teilmengen geschrieben.
- Jetzt müssen wir alle Werte in Teilmengen scannen. Das machen wir mit einem einzelnen Ausführungsagenten, der nach Abschluss von execution::bulk ausgeführt wird. Wir erstellen diesen Ausführungsagenten mit execution::then.
- execution::then nimmt einen Eingabesender und ein std::invocable und ruft das std::invocable mit dem vom Eingabesender gesendeten Wert auf. Innerhalb unseres std::invocable rufen wir std::inclusive_scan für Teilmengen auf, die die Eingabesender an uns senden werden.
- Dann geben wir Teilmengen zurück, die in der nächsten Phase benötigt werden.
- Schließlich führen wir eine weitere execution::bulk in der gleichen Form wie zuvor durch. In dieser execution::bulk verwenden wir die gescannten Werte in Teilbereichen, um die Summen aus anderen Kacheln in unsere Elemente zu integrieren und den inklusiven Scan abzuschließen.
- async_inclusive_scan gibt einen Sender zurück, der die Ausgabe std::span<double> sendet. Ein Verbraucher des Algorithmus kann zusätzliche Arbeit verketten, die das Scan-Ergebnis verwendet. Zu dem Zeitpunkt, an dem async_inclusive_scan zurückgegeben wird, ist die Berechnung möglicherweise noch nicht abgeschlossen. Tatsächlich hat sie möglicherweise noch nicht einmal begonnen.
- just(values): Gibt einen Sender ohne Abschlussplaner zurück, der die bereitgestellten Werte sendet. just ist eine Senderfabrik.
- bulk(input, shape, call): Gibt einen Sender zurück, der den aufrufbaren call beschreibt, der auf input gemäß shape aufgerufen wird.
- continues_on(input, scheduler): Gibt einen Sender zurück, der den Übergang vom Ausführungsagenten des Senders für die Eingabe zum Ausführungsagenten des Ziel-schedulers beschreibt.
- then(input, call): then gibt einen Sender zurück, der die Fortsetzung der Task des Senders für die Eingabe auf einem hinzugefügten Knoten des Aufrufs der bereitgestellten Funktion call beschreibt.
Hier hilft die Referenzimplementierung stdexec, wobei ich den Datentyp der verarbeiteten Elemente von double in int geändert habe:
// inclusiveScanExecution.cpp
#include <algorithm>
#include <exec/static_thread_pool.hpp>
#include <iostream>
#include <numeric>
#include <span>
#include <stdexec/execution.hpp>
#include <vector>
auto async_inclusive_scan(auto sch, // 2
std::span<const int> input, // 1
std::span<int> output, // 1
int init, // 1
std::size_t tile_count) // 3
{
std::size_t const tile_size = (input.size() + tile_count - 1) / tile_count;
std::vector<int> partials(tile_count + 1); // 4
partials[0] = İnit; // 4 STDEXEC :: Just (std :: move (kısmi)) // 5 | Stdexec :: continues_on (SCH) | Stdexec :: toplu (karo_count, // 6
[=](Std :: size_t i, std :: vektör & kısmi) {// 7 Arabalar Start = i * fayans_size; // 8 End Auto = std :: min (input.size (), (i + 1) * fayans_size); // 8 kısmi[i + 1] = *-STD :: Inclurment_scan (başlangıç (giriş) + başlangıç, // 9 başlangıç (giriş) + bitiş, // 9 start (çıktı) + start); // 9}) // 10 | Stdexec :: So (// 11
[](Std :: vektör kısmi &&) {std :: dahil Inclurment_scan (başlangıç (kısmi), son (kısmi), // 12 başlangıç (kısmi)); // 12 Dönüş std :: move (kısmi); // 13}) | Stdexec :: toplu (karo_count, // 14
[=](Std :: size_t i, std :: vektör & kısmi) {// 14 araba Start = i * fayans_size; // 14 End Auto = std :: min (input.size (), (i + 1) * fayans_size); // 14 saat :: for_each (başlangıç (çıktı) + başlat, başlat (çıktı) + bitiş, // 14
[&](int & e) {e = kısmi + E; } // 14); }) | Stdexec :: So (// 15
[=](Std :: vektör & & kısmi) {// 15 dönüş çıkışı; // 15}); // 15} int main () {std :: cout Giriş (30); Std :: IOTA (başlangıç (giriş), son (giriş), 0); (araba e: giriş) {std :: cout Çıktı (input.size ()); Exec :: Static_thread_pool Pool (8); Otomatik sch = pool.get_scaduler (); araba [out] = Stdexec :: sync_wait (async_inclusive_scan (Sch, giriş, çıktı, 0, 4)). Değer (); for (araba e: out) {std :: cout code>
İçinde main Olacak mı std::vector<int> Giriş 30 elementle oluşturuldu. . std::iota-Kunksiyonu doldurur input-Genercide iç sayıları olan vektör, 0. Bu nedenle program, konsoldaki taşıyıcının içeriğini yayınlar.
Diğerleri bir std::vector<int> output Aynı boyutta input-İfector kapsayıcı tarama ameliyatının sonuçlarını kurtarmak için oluşturuldu. . exec::static_thread_pool pool Görevlerin eşzamanlı olarak yürütülmesi için kullanılan iş parçacıklarına sahiptir. . get_scheduler-İplik havuzunun üyesinin işlevi bir zamanlayıcı nesne oluşturur sch.
İşlev async_inclusive_scan Zamanlayıcıyı kullanın schtaşıyıcı inputtaşıyıcı outputbaşlangıç değeri 0 ve bir dizi fayans 4. Bu işlev, belirtilen zamanlayıcı kullanarak eşzamansız kapsayıcı tarama ameliyatı gerçekleştirir ve bir geleceğe benzer bir nesne döndürür. İşlev stdexec::sync_wait Sonu için senkronize bekleyin async_inclusive_scan-Okalizasyon ve sonuç değişkendedir out Dağınık.
Son olarak, program taşıyıcının içeriğini sağlar out Konsolda:

Sırada ne var?
Bir sonraki blog yazımda, operatör aracılığıyla yayıncıların bir adım ve kompozisyonu yapacağım | açıklamak.
(RME)