[英]What is the best way to make bundles run parallel, threaded, in OSGI
我正在使用OSGI框架來創建一個嚴重依賴於數據包處理的應用程序。
每個捆綁包處理一個包,然后將其發送到下一個包。 我想要的是每個捆綁包都是並行的。 所以我想讓每個bundle都運行在它自己的Thread或多個Threads中。 “問題”是OSGI並不真正支持多線程。 在同一個JVM上運行的每個bundle只運行在1個Thread中,因此它遵循同步模型。
我的想法:所以應用程序的本質就像生產者消費者一樣。 Bundle A提供的服務有一個用於將包發送給A的方法,我們稱之為方法ain。 Bundle B也有同樣的設置,C也是如此。他們都有aa / b / cout方法,在這個方法中他們使用下一個bundle的服務,所以在A.aout你會像這樣調用bin:bservice.bin(package )。
因此,每個捆綁包都是消費者和數據包的生產者,這使我認為使用ExecutorService和BlockingQueues可能會有效,但我不太確定如何在捆綁包之間實現“正確”,並且所有捆綁包都是消費者和制作人我不太確定這是否是解決這個問題的最佳方法。
我希望你們能提供幫助和/或有任何建議。
- 編輯 -
捆綁AServiceImplementation
public class AServiceImplementation implements AService {
private BService bservice;
public void bindBService(BService service) {
bservice = service;
System.out.println("bundle gateway bound to b service");
}
public void unbindBService(BService service) {
this.bservice = null;
}
public void process(int id) {
bservice.transmitIn(id);
}
}
捆綁B BServiceImplementation
public class BServiceImplementation implements BService {
private CService cservice;
public void bindCService(CService service) {
cservice = service;
System.out.println("bundle gateway bound to b service");;
}
public void unbindCService(CService service) {
this.cservice = null;
}
public void transmitIn(int id){
// So if I would implement it THIS is where I would assign the data to
// a thread to get it processed in the process method.
// but doesn't that make THIS method, transmitIn a bottleneck since all packages
// need to pass through here?
process(id);
}
public void process(int id) {
// Lots of processing happens here
}
}
我真的不明白如何使它成為例如bundle A通過transmitIn方法將數據傳輸到bundle B而沒有transmitIn是一個瓶頸,因為我將'workdistribution'設置為該方法中的不同線程(如下所示)上面的代碼)
啊,一個充分的誤解。 OSGi不關心你使用並發性做什么,它的一大優勢是它不像許多應用程序服務器那樣改變計算模型。 從捆綁包或包的角度來看,線程完全不相關。 所以任何Java解決方案都適用於此
在您的示例中,所有處理都將在初始調用程序線程上進行,即調用AServiceImplementation的線程。 如果你想並行處理,你可以為你提交的每個任務使用執行程序,這就是Executors派上用場的模式。 這使處理異步,因此您沒有返回值。 注意,處理將受到您提供的Executor中可用線程數的限制。 您還必須非常小心地編寫處理代碼,以便為非局部變量處理正確的同步。
另一種方法是排隊。 每個服務調用都會創建一個包含任務信息的對象,然后將該對象發布到阻塞隊列中。 在OSGi激活器中,您創建一個讀取隊列並對其進行處理的線程。 在這個模型中,您可以在不擔心(過多)並發性的情況下進行處理,因為所有處理總是在同一個線程中進行。 出於性能原因,您可以啟動多個線程,但處理起來要困難得多。
但是,我的建議是跳過此優化並盡可能簡化您的系統。 如果它運行,並且您發現存在性能問題,則可以盡早開始擔心這些問題。 根據您目前的理解水平,我擔心您有機會為“可能”問題創建高度復雜的解決方案。
“問題”是OSGI並不真正支持多線程。 在同一個JVM上運行的每個bundle只運行在1個Thread中,因此它遵循同步模型。
對不起,但這是一個完全的誤解。 讓我引用OSGi Core規范,第4.2.7節:
OSGi框架在多線程環境中運行。 框架啟動后,它將啟動捆綁包,這些捆綁包將被激活。 激活的bundle通常會啟動后台線程或對來自其他bundle的事件做出反應。 也就是說,在start方法返回之后,框架已經轉移到ACTIVE狀態,並且許多bundle可以在不同的線程上忙碌。
換句話說,您可以自由地創建適合您需求的任何線程解決方案。 這不是OSGi問題。
更新:
您的服務實現可以像這樣共享ExecutorService:
public class BServiceImplementation implements BService {
private ExecutorService executorService;
private CService cservice;
public void bindCService(CService service) {
cservice = service;
System.out.println("bundle gateway bound to b service");
}
public void bindExecutorService(ExecutorService executorService) {
this.executorService = executorService;
}
public void unbindCService(CService service) {
this.cservice = null;
}
public void transmitIn(final int id) {
executorService.submit(new Runnable() {
@Override
public void run() {
process(id);
}
});
}
public void process(int id) {
// Lots of processing happens here
}
}
然后讓另一個bundle將ThreadPoolExecutor暴露為ExecutorService。
我想知道你是否只是不能在你的激活方法中使用以下代碼行:
public void activate(){
new Thread(this).start();
}
現在你只需要捆綁Runnable,並實現run()方法。 在此run方法中,您可以讓bundle的使用者端等待新任務。
然后讓每個消費者(這是通信捆綁的服務端)定義一個BlockingQueue。 當bundle(producer-end)綁定到某個服務時,您還要確保保留對此隊列的引用。 這樣每個bundle應該只有一個隊列。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.