Paralel yürütme ilkesi ile yerinde std :: transform kullanabilir miyim?


11

Yanılmıyorsam, bir giriş ve çıkış yineleyicisi ile aynı aralığı kullanarak yerindestd::transform performans gösterebilirim . Bazı nesnelerim olduğunu varsayalım , o zaman yazardımstd::vectorvec

std::transform(vec.cbegin(),vec.cend(),vec.begin(),unary_op)

uygun bir tekli işlem kullanarak unary_op.

C ++ 17 standardını kullanarak, std::execution::parilk argüman olarak oraya yapıştırarak dönüşümü paralel olarak yürütmek istiyorum . Bu, fonksiyonun cppreference makalesindestd::transform aşırı yük (1) 'den (2)' ye gitmesini sağlayacaktır . Ancak bu aşırı yüklenmenin yorumları şöyle diyor:

unary_op[...] uç yineleyiciler de dahil olmak üzere yineleyicileri geçersiz kılmamalı veya ilgili aralıkların öğelerini değiştirmemelidir. (C ++ 11'den beri)

"Herhangi bir öğeyi değiştir" gerçekten algoritmayı yerinde kullanamayacağım anlamına mı geliyor yoksa yanlış yorumladığım farklı bir ayrıntıdan mı bahsediyor?

Yanıtlar:


4

Burada standart teklif etmek

[Alg.transform.1]

op [...] yineleyicileri veya alt aralıkları geçersiz kılmaz veya aralıklardaki öğeleri değiştirmez

bu unary_op, argüman olarak verilen değeri veya kabın kendisini değiştirmenizi yasaklar .

auto unary_op = [](auto& value) 
{ 
    value = 10;    // this is bad
    return value;
}

auto unary_op = [&vec](auto const& value) 
{ 
    vec[0] = value;   // also bad
    return value;
}

auto unary_op = [&vec](auto& value) 
{ 
    vec.erase(vec.begin());   // nope 
    return value;
}

Ancak, follwing tamam.

auto unary_op = [](auto& value)  // const/ref not strictly needed
{         
    return value + 10;   // totally fine
}

auto unary_op = [&vec](auto& value)
{         
    return value + vec[0];   // ok in sequential but not in parallel execution
}

Independent UnaryOperationElimizdeki

[Alg.transform.5]

sonuç, tekli dönüşüm durumunda birinciye eşit olabilir [...].

yani yerinde işlemlere açıkça izin verilir.

şimdi

[Algorithms.parallel.overloads.2]

Aksi belirtilmedikçe, ExecutionPolicy algoritma aşırı yüklerinin semantiği, aşırı yüklenmeleriyle aynıdır.

yürütme ilkesinin algoritmada kullanıcı tarafından görülebilir hiçbir farkı olmadığı anlamına gelir. Algoritmanın, bir yürütme ilkesi belirtmediğiniz gibi aynı sonucu vermesini bekleyebilirsiniz.


6

Farklı bir ayrıntıdan bahsettiğine inanıyorum. Dizinin unary_opbir elemanını alır ve bir değer döndürür. Bu değer (tarafından transform) hedef diziye kaydedilir.

Yani bu unary_opiyi olur:

int times2(int v) { return 2*v; }

ama bu olmazdı:

int times2(int &v) { return v*=2; }

Ama bu tam olarak sorduğunuz şey değil. unary_opSürümünü transformaynı kaynak ve hedef aralığa sahip bir paralel algoritma olarak kullanıp kullanamayacağınızı bilmek istiyorsunuz . Ben neden görmüyorum. transformkaynak dizinin tek bir öğesini hedef dizinin tek bir öğesiyle eşleştirir. Bununla birlikte, unary_opgerçekten tekli değilseniz , (yani, sekanstaki diğer öğelere referans verir - sadece okuyor olsa bile, bir veri yarışına sahip olursunuz).


1

Eğer anılan bağlantının örnekte görebileceğiniz gibi, herhangi unsurları değiştirerek değil unsurları değiştirerek her türlü anlama geliyor:

İşlevin imzası aşağıdakine eşit olmalıdır:

Ret fun(const Type &a);

Bu, elemanlar üzerinde değişiklik yapılmasını içerir. En kötü durumda, hedef için aynı yineleyiciyi kullanırsanız, değişiklik, yineleyicilerin geçersiz kılınmasına neden olmamalıdır.push_back muhtemelen yineleyicilerin geçersiz kılınmasına neden olacak vektör veya erasing içinvector .

Canlı yapmamanız gereken bir hata örneğine bakın .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.