2010-12-01 19 views
9

Belirli bir saatte bir şeyin hesaplanması gereken bir uygulama var. Bu hesaplama fonksiyonu, bu hesaplamaları 4 iş parçacığı üzerinde çalıştırmayı mümkün kılan @Async (Spring Framework'den) ek açıklamasına sahiptir. Sorun şu ki bu hesaplamaların yaklaşık 40000'üne ihtiyacım var ve tüm hesaplamaların başlangıcı ile bitişi arasındaki süreyi bilmek istiyorum, bu yüzden hesaplama işlevlerini çağıran döngü öncesi ve sonrası zamanı görüyorum. Ama şimdi tüm hesaplamalar bir sıraya konur, bu yüzden döngü hemen biter ve zaman 1 saniye gibi bir şeydir, hesaplamaların tamamlanması birkaç saat sürer. Yaklaşık 100'e kadar bir maksimum kuyruk boyutu ayarlamayı denedim (bellek kullanımını azaltmak için de iyi), ancak bu, aynı zamanda son çözümlemeyi toplam süre içinde kaçıracağımdan da bir çözüm değil. Yürütme kodunu tüm iş parçacıkları işlerini bitirinceye kadar sadece döngüden sonra duraklatmanın bir yolu var mı, ancak yine de @ Async ek açıklamasını kullanabiliyor musunuz?@Async, bir iş parçacığının diğer iş parçacığı bitinceye kadar devam etmesini önler

yürütülüyor sınıfı::

public class Foo { 
    public void executeBlaALotOfTimes() { 
     long before = System.currentTimeMillis(); 

     for (int i = 0; i<40000; i++) { 
      executeBla(); 
     } 

     long after = System.currentTimeMillis(); 

     System.out.println("Time it took for a lot of bla to execute: " + (after - before)/1000.0 + " seconds."); 
    } 
} 

Ve hesaplamaları yapar sınıfı:

@Service 
public class Bar { 
    @Async 
    public void executeBla() { 
     System.out.println("Bla!"); 
    } 
} 

Bu aşağıdaki çıkışı neden olur

Bu

aynı sorunu göstermektedir bazı koddur (Foo'daki kodu sonsuz hızlı yürütürse):

 
Time it took for a lot of bla to execute: 0.0 seconds. 
Bla! 
Bla! 
Bla! 
Bla! 
. 
. 
. 
etc 
+0

Async' @ bu bahar 'mı? – skaffman

+0

Üzgünüm, evet, bu Spring @Async – FinalArt2005

+0

kullanıyor Bize '@ Async' yöntemini ve nasıl çağırdığınızı bize göster. – skaffman

cevap

29

Yürütme işlemlerinin bitmesini beklemeniz gerekiyorsa, bir Future döndürme değeri olarak döndürebilirsiniz, örn.

public void executeBlaALotOfTimes() { 
    long before = System.currentTimeMillis(); 

    Collection<Future<Void>> futures = new ArrayList<Future<Void>>(); 

    for (int i = 0; i<40000; i++) { 
     futures.add(executeBla()); 
    } 

    for (Future<Void> future : futures) { 
     future.get(); 
    } 

    long after = System.currentTimeMillis(); 

    System.out.println("Time it took for a lot of bla to execute: " + (after - before)/1000.0 + " seconds."); 
} 

Burada, birinci döngü yangınları kapalı: orada iade edilen hiçbir gerçek değer, ama hala tüm infazlar bitirmek için arama kodu beklemek sağlayacak beri

@Async 
public Future<Void> executeBla() { 
    System.out.println("Bla!"); 
    return new AsyncResult<Void>(null); 
} 

Bu, biraz yapay async görevleri ve gelecekleri bir listede saklar. Saniye döngüsü daha sonra her birinin bitmesini bekleyen gelecekleri tekrarlar.

1

Bir alternatif bir ListenableFuture döndürmek ve bir CountDownLatch kullanmaktır.

@Async 
public ListenableFuture<Void> executeBla() { 
    try { 
     System.out.println("Bla!"); 
     return AsyncResult.forValue(null); 
    } catch (Throwable t) { 
     return AsyncResult.forExecutionException(t); 
    } 
} 

Bu senaryo açıkça her gelecek için future.get() arama önlemek için izin verir. Bunu, tam olarak bu amaç için oluşturulmuş olan CountDownLatch'u azaltan başarı ve hata geri çağrıları ekleyerek gerçekleştirebilirsiniz.

public void executeBlaALotOfTimes() { 
    long before = System.currentTimeMillis(); 

    int numExecutions = 40000; 
    CountDownLatch countDownLatch = new CountDownLatch(numExecutions); 

    for (int i = 0; i<numExecutions; i++) { 
     ListenableFuture<Void> future = executeBla(); 
     future.addCallback(
      aVoid -> countDownLatch.countDown(), 
      throwable -> countDownLatch.countDown() 
     ); 
    } 

    try { 
     countDownLatch.await(); 
    } catch (InterruptedException e) { 
     // Handle exception 
    } finally { 
     long after = System.currentTimeMillis(); 
     System.out.println("Time it took for a lot of bla to execute: " + (after - before)/1000.0 + " seconds."); 
    } 

}

İlgili konular