[英]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.