2014-05-01 89 views
9

我最近讀到Quasar它提供了「輕量級」 /轉到樣「用戶模式」線程到JVM(它也有一個Erlang的啓發演員系統,如阿卡,但這不是主要的問題)輕量級線程

例如:

package jmodern; 

import co.paralleluniverse.fibers.Fiber; 
import co.paralleluniverse.strands.Strand; 
import co.paralleluniverse.strands.channels.Channel; 
import co.paralleluniverse.strands.channels.Channels; 

public class Main { 
    public static void main(String[] args) throws Exception { 
     final Channel<Integer> ch = Channels.newChannel(0); 

     new Fiber<Void>(() -> { 
      for (int i = 0; i < 10; i++) { 
       Strand.sleep(100); 
       ch.send(i); 
      } 
      ch.close(); 
     }).start(); 

     new Fiber<Void>(() -> { 
      Integer x; 
      while((x = ch.receive()) != null) 
       System.out.println("--> " + x); 
     }).start().join(); // join waits for this fiber to finish 
    } 
} 

據我明白上面不產卵任何JVM /內核線程,所有在用戶模式線程完成(或使他們權利要求)的代碼,其被認爲是便宜(只是如果我的理解正確,就像Go例程一樣)

我的問題是 - 據我瞭解,在Akka中,所有東西仍然基於JVM線程,大部分時間映射到本地OS內核線程(例如, POSIX系統中的線程),例如據我所知,沒有用戶模式的線程/像Akka中的協程/輕量級線程一樣,我理解正確嗎?

如果是這樣,那麼你知道它是否是設計選擇嗎?或者未來有計劃在阿卡製造像輕量級的線程?我的理解是,如果你有一百萬個Actor,但其中大多數都是阻塞的,那麼Akka可以用更少的物理線程處理它,但是如果它們中的大多數都是非阻塞的,並且你仍然需要系統的一些響應(例如服務數百萬個用於傳輸某些數據的小型請求),那麼我可以看到用戶模式線程實現的好處,它可以讓更多的「線程」以更低的開銷和終止成本活着(當然,唯一的好處是對許多客戶均勻分配響應能力,但響應仍然很重要)

我的理解是正確的或多或少?如果我錯了,請糾正我。

*我可能完全混淆了用戶模式的線程與go/co-routines和輕量級線程,上面的問題依賴於我的不理解,他們都是相同的。

+1

這是我從我的Python經驗中記得的。這不是一個直接的答案,但它可能是有用的。用戶/輕量級線程和實際系統線程都有其用途。歸結起來,它們都提供了併發性,但只有系統線程提供了並行性。所以如果你在進行繁重的計算,你不會從使用用戶線程獲得任何提升,但是你將從系統線程中獲益。在不同的情況下,只有一個CPU內核,並且你想要一臺服務器,使用用戶線程是唯一的解決方案。 – Andrey

+0

是的,這也是我所理解的,例如用戶線程僅適用於提供CPU的「良好利用率」,例如,在2個用戶線程之間切換,有時會阻止IO比使用完整線程便宜。你不會得到並行性,但是如果我理解正確,你會得到更好的CPU利用率 –

+0

請看看我的答案,它可以幫助你:http://stackoverflow.com/questions/29680718/relinquish-the-thread -cpu-until-async-call-completion-in-akka-and-java/29748613#29748613 – circlespainter

回答

8

阿卡是一個非常靈活的庫,它允許您使用安排演員一個簡單的特質ExecutionContext,正如你所看到的,接受Runnable S和以某種方式執行(本質上是通過性狀鏈歸結到)他們。所以,就我所知,很可能可以寫一個類似Quasar的綁定,並將其用作Akka actor的「後端」。

但是,類星體和類似的庫可能爲光纖之間的通信提供特殊的工具。我也不知道他們將如何處理像I/O這樣的阻塞任務,可能他們也會有這樣的機制。我不確定阿卡能否因此正確運行綠線。類星體也似乎依賴字節碼工具,這是一種相當先進的技術,可能會有很多隱含的問題阻止它支持阿卡。

但是,在使用Akka actor時,您不應該擔心線程的輕量級。實際上,Akka完全可以在單個系統上創建數百萬演員(請參閱here),所有這些演員都可以正常工作。

這是通過對特殊類型的線程池(如fork-join線程池)的巧妙調度實現的。這意味着,除非演員在某些長時間運行的計算中被阻止,否則他們可以運行多個線程,這些線程的數量遠遠少於這些actor的數量。例如,您可以創建一個最多使用8個線程(每個8核處理器的核心一個)的線程池,並且所有參與者活動都將在這些線程上進行調度。

Akka靈活性允許您配置精確調度程序以用於特定參與者(如果需要)。您可以爲演員保留長時間運行的任務(如數據庫訪問)創建專用調度器。有關更多信息,請參閱here

因此,簡而言之,不,你不需要爲演員的userland線程,因爲演員不映射一個-to-one的本地線程(除非你他們,那就是,但這應該不惜一切代價避免)。

+0

線程更少 - 給定相同延遲的上下文切換更少。所以,簡而言之,是的,如果可以的話,你可以考慮使用userland線程。 –

+0

「這是通過對特殊類型的線程池的巧妙調度實現的」< - 我可以從哪裏獲得更多關於如何實際完成的信息(以最簡單的形式)? – Franz

+0

@Franz我不確定最簡單的形式,但是你可以從akka開始閱讀[關於調度員](http://doc.akka.io/docs/akka/2.4/scala/dispatchers.html) docs,然後直接繼續[fork-join thread pool]的文檔(https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ForkJoinPool.html)。你也可以谷歌關於fork-join線程池,你會發現很多教程和解釋。 –

2

阿卡演員基本上異步,這就是爲什麼你可以有很多人,而類星體演員(是,類星體提供者實現過),這是非常接近Erlang的,是同步阻塞,但它們使用的是纖維而不是Java(即目前的OS)線程,所以仍然可以擁有與async相同的性能,但編程風格與使用常規線程和阻止調用一樣簡單。

通過集成處理I/O:Quasar includes a framework to convert both async and sync APIs into fiber-blockingComsat包括許多此類集成已準備好(其中一個與Java NIO直接包含在Quasar中)。

My reply to another question包含更多信息。