2016-03-27 22 views
9

C++' da paralel olarak döngüleri temel alan ve aralıkları gibi döngüleri hesaplamak için hafif, düz bir yol olup olmadığını merak ediyorum. Böyle bir şeyi nasıl uygularsın? Scala'dan haritayı, filtreyi ve foreach işlevlerini biliyorum belki de bu paralelleri gerçekleştirmek mümkün olabilir mi? Bunu C++ 'da başarmanın kolay bir yolu var mı? Birincil plattform Linux'tur, ancak çapraz-plattform çalışıyorsa güzel olur.C++ 'da Paralel Döngüler

+0

konuları kullanarak iyi bir seçenektir. –

+0

Konuları başlatmak gerçekten çok pahalı değil mi? – Exagon

+1

Çatal() çağrısıyla karşılaştırın. Konuları, kendi bilgisayarları, kayıtları ve yığınları dışında, ana iş parçasından paylaştıkları için pahalı değildir. –

cevap

8

Platformunuz nedir? C++'nin bir parçası olmasa da, OpenMP'a bakabilirsiniz. Ancak derleyiciler tarafından yaygın olarak desteklenmektedir.

Döngüler için döngülere gelince, bkz. Ör., Using OpenMP with C++11 range-based for loops?.

Ayrıca, http://www.open-std.org numaralı belgede, paralel yapıları/algoritmaları gelecekteki C++'ye dahil etme çabalarını gösteren birkaç belge gördüm, ancak geçerli durumlarının ne olduğunu bilmiyorum.

Sadece bazı örnek kod ekleyerek GÜNCELLEME:

template <typename RAIter> 
void loop_in_parallel(RAIter first, RAIter last) { 
    const size_t n = std::distance(first, last); 

    #pragma omp parallel for 
    for (size_t i = 0; i < n; i++) { 
     auto& elem = *(first + i); 
     // do whatever you want with elem 
    } 
} 

iplik sayısı OMP_NUM_THREADS ortam değişkeni üzerinden çalışma zamanında ayarlanabilir. C++ çalışma zamanının paralelliği kontrol etmesine izin verirseniz, burada iyi bir uyum olabilir

+0

Döngünün içinde çok pahalı olmayan bir işlem yaptığımı söyleyelim, döngüyü ikiye bölmek mümkün mü? İş parçacığında diğer yarısı diğerlerini mi? Konu 3 ile aynı şekilde mi? – Exagon

+0

Neyi tekrarlıyorsunuz? Döngü için dizin kullanabilir misin? –

+0

@Exagon Bu, hangi şekilde iş parçacığından iş aldığınıza bağlıdır. İşi bölebileceğiniz döngülerde koşullar yaratabilirsiniz. –

3

Bu, işlemleri aynı anda gerçekleştirmek için kullanılabilen threads özellikle pthreads kitaplık işlevi kullanılarak yapılabilir.

Burada onlar hakkında daha fazla bilgi edinebilirsiniz: http://www.tutorialspoint.com/cplusplus/cpp_multithreading.htm

std :: iplik de kullanılabilir: Aşağıda

http://www.cplusplus.com/reference/thread/thread/ i içine diziyi bölmek için her dişin diş kimliği kullanan bir koddur iki yarısı: Eğer -lpthread bayrağını kullanmak zorunda derlenirken

#include <iostream> 
#include <cstdlib> 
#include <pthread.h> 

using namespace std; 

#define NUM_THREADS 2 

int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 

void *splitLoop(void *threadid) 
{ 
    long tid; 
    tid = (long)threadid; 
    //cout << "Hello World! Thread ID, " << tid << endl; 
    int start = (tid * 5); 
    int end = start + 5; 
    for(int i = start;i < end;i++){ 
     cout << arr[i] << " "; 
    } 
    cout << endl; 
    pthread_exit(NULL); 
} 

int main() 
{ 
    pthread_t threads[NUM_THREADS]; 
    int rc; 
    int i; 
    for(i=0; i < NUM_THREADS; i++){ 
     cout << "main() : creating thread, " << i << endl; 
     rc = pthread_create(&threads[i], NULL, 
          splitLoop, (void *)i); 
     if (rc){ 
     cout << "Error:unable to create thread," << rc << endl; 
     exit(-1); 
     } 
    } 
    pthread_exit(NULL); 
} 

Ayrıca hatırlıyorum. Ideone üzerinde çözüme

Bağlantı: http://ideone.com/KcsW4P

+1

Evet, elde edeceğiniz fonksiyonda 'başlangıç ​​dizini 've' end endeksini belirtebilir ve kullanacağınız her iş parçacığı için buna göre değiştirebilirsiniz. – uSeemSurprised

+1

'pthread_create' işlevi, iş parçacığınızın kullanmasını istediğiniz işlevin adını içeren bir argümanı yan yana alır, istenen sonucu elde etmek için bu işlev argümanlarını değiştirebilirsiniz. – uSeemSurprised

+3

neden std :: thread' olduğunda pthreads kullanmak ister? –

8

. cppreference.com gelen

Örnek: Şimdi kullanabilir C++ 17 paralel algoritmaları ile

#include <iostream> 
#include <vector> 
#include <algorithm> 
#include <numeric> 
#include <future> 

template <typename RAIter> 
int parallel_sum(RAIter beg, RAIter end) 
{ 
    auto len = end - beg; 
    if(len < 1000) 
     return std::accumulate(beg, end, 0); 

    RAIter mid = beg + len/2; 
    auto handle = std::async(std::launch::async, 
           parallel_sum<RAIter>, mid, end); 
    int sum = parallel_sum(beg, mid); 
    return sum + handle.get(); 
} 

int main() 
{ 
    std::vector<int> v(10000, 1); 
    std::cout << "The sum is " << parallel_sum(v.begin(), v.end()) << '\n'; 
} 
+0

vay teşekkür ederim bu – Exagon

+0

kullanacağım düşünüyorum C++ nasıl paralel görevleri ve uyumsuzlukları ele alır? – Exagon

+1

std :: async() 'işlevinin ilk parametresi, çerçeveye hangi özgürlüğü verdiğinizi belirtir (öncelikle ön plan iş parçacığı kullanımına izin verilip verilmediğini belirtir). Arka plan için ne yaptıklarına gelince, derleyiciye özgüdür, ancak büyük olasılıkla çoğu derleyicide, N = kutucuktaki CPU çekirdek sayısı olan bir tekli iplik havuzu olacaktır. Şimdiye kadar geldiğim en iyi kullanım belgeleri son Mayer'in kitabındaki eşzamanlılık bölümüdür. – bobah

5

:

std::vector<std::string> foo; 
std::for_each(
    std::execution::par_unseq, 
    foo.begin(), 
    foo.end(), 
    [](auto&& item) 
    { 
     //do stuff with item 
    }); 

paralel döngüler hesaplamak için. İlk parametre execution policy

+0

Derleyiciler aslında şu anda bunu destekliyor mu? – nitronoid

+0

Intel C++ derleyici, eğer bir öğrenciyseniz, ücretsiz olarak alabilirsiniz. – Kaznov

1

C++ 11 ile bir for döngüsünü yalnızca birkaç satırlık kodla paralel hale getirebilirsiniz.

/// Basically replacing: 
void sequential_for(){ 
    for(int i = 0; i < nb_elements; ++i) 
     computation(i); 
} 

/// By: 
void threaded_for(){ 
    parallel_for(nb_elements, [&](int start, int end){ 
     for(int i = start; i < end; ++i) 
      computation(i); 
    }); 
} 

Veya bir sınıf Withing:

struct My_obj { 

    /// Replacing: 
    void sequential_for(){ 
     for(int i = 0; i < nb_elements; ++i) 
      computation(i); 
    } 

    /// By: 
    void threaded_for(){ 
     parallel_for(nb_elements, [this](int s, int e){ this->process_chunk(s, e); }); 
    } 

    void process_chunk(int start, int end) 
    { 
     for(int i = start; i < end; ++i) 
      computation(i); 
    } 
}; 

Bunu yapmak için, sadece aşağıdaki kodu koymak gerekir Bu küçük parçalar halinde döngü ve bir konuya her bir alt döngü atamak böler Bir üstbilgi dosyası ve bunu kullanacaksınız:

#include <algorithm> 
#include <thread> 
#include <functional> 
#include <vector> 

/// @param[in] nb_elements : size of your for loop 
/// @param[in] functor(start, end) : 
/// your function processing a sub chunk of the for loop. 
/// "start" is the first index to process (included) until the index "end" 
/// (excluded) 
/// @code 
///  for(int i = start; i < end; ++i) 
///   computation(i); 
/// @endcode 
/// @param use_threads : enable/disable threads. 
/// 
/// 
static 
void parallel_for(unsigned nb_elements, 
        std::function<void (int start, int end)> functor, 
        bool use_threads = true) 
{ 
    // ------- 
    unsigned nb_threads_hint = std::thread::hardware_concurrency(); 
    unsigned nb_threads = nb_threads_hint == 0 ? 8 : (nb_threads_hint); 

    unsigned batch_size = nb_elements/nb_threads; 
    unsigned batch_remainder = nb_elements % nb_threads; 

    std::vector<std::thread> my_threads(nb_threads); 

    if(use_threads) 
    { 
     // Multithread execution 
     for(unsigned i = 0; i < nb_threads; ++i) 
     { 
      int start = i * batch_size; 
      my_threads[i] = std::thread(functor, start, start+batch_size); 
     } 
    } 
    else 
    { 
     // Single thread execution (for easy debugging) 
     for(unsigned i = 0; i < nb_threads; ++i){ 
      int start = i * batch_size; 
      functor(start, start+batch_size); 
     } 
    } 

    // Deform the elements left 
    int start = nb_threads * batch_size; 
    functor(start, start+batch_remainder); 

    // Wait for the other thread to finish their task 
    if(use_threads) 
     std::for_each(my_threads.begin(), my_threads.end(), std::mem_fn(&std::thread::join)); 
}