26 Mart 2013 Salı

Paralel Örüntüler

Aşağıda paralel çalışırken karşıma çıkan örüntülerle ilgili notlarım var.

ThreadPool ile Birbirinden Bağımsız İşlerin Çalıştırılması
Bu en kolay örüntü. ExecutorService'e verilen işin sonucu beklememiz gerekmiyor. Özellikle execute() metodu bu örüntü ile kullanmak için yazılmış.

ThreadPool Olmadan Çalıştırılan Tek Bir İşin Bitmesinin Beklenmesi
Hemen hemen tüm thread kütüphaneleri join isminde bir metod sağlıyorlar. Aşağıdaki bir kaç örnek var.
C#
Örneği buradan aldım.

ThreadPool ile Çalıştırılan Tek Bir İşin Bitmesinin Beklenmesi
C#
Örneği buradan aldım.

Eğer TPL kullanılıyorsa aşağıdaki gibi yapılabilir.

Task t = Task.Factory.StartNew(() => Console.WriteLine("Started"););
t.Wait();

ThreadPool ile Çalıştırılan Tek Bir İşin Bitmesinin Beklenmesi ve Sonucunun Alınması
Java

Executor.execute metodu ile
Bu örüntüde FutureTask kullanılıyor. FutureTask ile işin bitip bitmediği kontrol edilebilir ve gerekirse iş iptal de edilebilir ancak dikkat edilmesi gereken bir nokta var. FutureTask tekrar tekrar kullanılamaz

 FutureTask ya Runnable ya da Callable arayüzününden birisini saran bir sınıf. Runnable arayüzü en eski arayüz ve bir sonuç tipi döndüremiyor çünkü sadece void run() metoduna sahip. Callable arayüzü ise bir sonuç döndürebiliyor çünkü V call() metoduna sahip.

Buradan aldığım örnekte cache içinde önceden hesaplanmış bir sonuç varsa kullanılıyor. Yoksa hesaplam işleminin bitmesi bekleniyor.

public class Cache<K, V> {
    ConcurrentMap<K, FutureTask<V>> map = new ConcurrentHashMap();
    Executor executor = Executors.newFixedThreadPool(8);
   
    public V get(final K key) {
        FutureTask<V> f = map.get(key);
        if (f == null) {
            Callable<V> c = new Callable<V>() {
            public V call() {
                // return value associated with key
            }
        };
        f = new FutureTask<V>(c);
        FutureTask old = map.putIfAbsent(key, f);
        if (old == null)
            executor.execute(f);
        else
            f = old;
        }
        return f.get();
    }
}
Executor.submit metodu ile
Örneği buradan aldım.Future.get() metodu bu sefer timeout mekanizması ile beraber kullanılıyor.

ThreadPool ile Çalıştırılan Birden Fazla İşin Sonucunun Alınması
Java
Bu örüntüde CompletionService kullanılıyor. Buradan aldığım örnekte tek bir işin sonucunun gelmesi ile diğer görevler iptal ediliyor.
void solve(Executor e, Collection<Callable<Result>> solvers)
    throws InterruptedException {
        CompletionService<Result> ecs = new ExecutorCompletionService<Result>(e);
        int n = solvers.size();
        List<Future<Result>> futures = new ArrayList<Future<Result>>(n);
        Result result = null;
        try {
            for (Callable<Result> s : solvers)
                futures.add(ecs.submit(s));
            for (int i = 0; i < n; ++i) {
                try {
                    Result r = ecs.take().get();
                    if (r != null) {
                        result = r;
                        break;//Diğer işlerin bitmesini bekleme
                    }
                } catch(ExecutionException ignore) {}
            }
        }
        finally {
            for (Future<Result> f : futures)
                f.cancel(true);
        }
        if (result != null)
            use(result);
}
Yukarıdaki kodda dikkat edilmesi gereken nokta Future.cancel() metodunun çağırılması. Bu metod alt tarafta Thread.interrupt() metodunu çağırır. Eğer bizim threadimiz aşağıdaki gibi çalışmıyorsa aslında Future.cancel() metodu işe yaramayabilir.

while(!Thread.currentThread().isInterrupted()){
    try{
        // birşeyler yap
    }
    catch(InterruptedException e){
        Thread.currentThread().interrupt();
    }
}

Paralel For ve ForEach Döngüleri
“Parallel.For” for Java? sorusunda bazı döngülerin nasıl paralel çalıştırılabileceği gösterilmiş.Aşağıdaki soruda C# ile for each döngüsü kurulurken, döngüdeki değişkenin kullanılmaması gerektiği gösterilmiş. Örnek:

Hiç yorum yok:

Yorum Gönder