简体   繁体   English

Android中的多线程

[英]Multithreading in Android

I'm trying to multithread some OpenCV4Android code. 我正在尝试多线程一些OpenCV4Android代码。 I divide a 432x432 image into 9 144x144 segments and pass each to a different thread: 我将432x432图像分成9个144x144段并将每个图像传递给不同的线程:

Thread[] threads = new Thread[9];
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        threads[3*i+j] = new Thread(new MyThread(image.rowRange(144*i, 144*(i+1)).colRange(144*j, 144*(j+1))));
        threads[3*i+j].start();
    }
}

for (Thread thread : threads) try {thread.join();} catch (InterruptedException e) {};

Here is the thread class: 这是线程类:

public class MyThread implements Runnable {
    final Mat block;

    public MyThread(Mat block) {
        this.block = block;
    }

    public void run() {
        /* do image processing on block */
        Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(19,19));
        Mat closed = new Mat();
        Imgproc.morphologyEx(block, closed, Imgproc.MORPH_CLOSE, kernel);
        Core.divide(block, closed, block, 1, CvType.CV_32F);
        Core.normalize(block, block, 0, 255, Core.NORM_MINMAX);
        block.convertTo(block, CvType.CV_8UC1);     
        Imgproc.threshold(block, block, -1, 255, Imgproc.THRESH_BINARY_INV+Imgproc.THRESH_OTSU);
    }
}

I have two issues: 我有两个问题:

  1. Although the threads are modifying the individual blocks correctly, the modifications are not showing up in the final image. 尽管线程正在正确地修改各个块,但修改并未显示在最终图像中。 This would make sense if Mat block were passed by value to the thread, but Java should be passing its reference to the thread instead. 如果Mat block通过值传递给线程,这将是有意义的,但Java应该将其引用传递给线程。

  2. The runtime is longer than the unthreaded code - in my emulator, it goes up from ~1200 to ~1500 ms. 运行时比无螺纹码 -在我的模拟器,它从1200〜上升到〜1500毫秒。 Is this a problem with the emulator, or is multithreading a really bad idea here for some reason? 这是模拟器的问题,还是因为某种原因多线程是一个非常糟糕的主意?

I've no experience with OpenCV, so I'll address only the second issue. 我没有OpenCV的经验,所以我只会解决第二个问题。

A thread needs a CPU to run (or a core which acts as a virtual CPU). 线程需要CPU运行(或者作为虚拟CPU的核心)。 So, you will never have more threads running in silmultaneous then the real number of cores available in the device. 因此,您将永远不会有更多的线程同时运行设备中可用的实际内核数量。

Let's assume you have a device with 2 cores and you split the work in 9 threads. 假设您有一个具有2个内核的设备,并将工作拆分为9个线程。 The final result is that only 2 out of 9 threads will run in silmultaneous, while the remaining 7 will be in the queue waiting for their turn to have CPU. 最终结果是9个线程中只有2个将同时运行,而剩下的7个将在队列中等待轮到CPU。

As there is a cost in Thread creation and switching, the overall performance result would be worse then having only 2 threads. 由于线程创建和切换存在成本,因此整体性能结果将比只有2个线程更糟糕。

If you are spliting the work between threads for performance reasons, don't make more threads then the number of cores in the device. 如果出于性能原因在线程之间拆分工作,请不要在设备中创建更多的线程数。

I believe that most devices on market are limited to 1 or 2 cores ... 我相信市场上的大多数设备都限制在1或2个核心......

Regards 问候

The first problem was being caused by the conversion of the block Mat to a different type in this section: 第一个问题是由于block Mat转换为本节中的其他类型:

Core.divide(block, closed, block, 1, CvType.CV_32F);
Core.normalize(block, block, 0, 255, Core.NORM_MINMAX);
block.convertTo(block, CvType.CV_8UC1);     

I'm not sure why this should be a problem, but I fixed it by storing the intermediate floating-point matrix in closed and only putting the final answer back into block : 我不确定为什么这应该是一个问题,但我通过将中间浮点矩阵存储在closed并仅将最终答案放回block修复它:

Core.divide(block, closed, closed, 1, CvType.CV_32F);
Core.normalize(closed, block, 0, 255, Core.NORM_MINMAX, CvType.CV_8U);

Luis has addressed the second problem. 路易斯解决了第二个问题。 And i think the first issue is because that you process a new Mat to the thread, the modification on the new Mat will not effect the old one. 我认为第一个问题是因为你处理一个新的Mat到线程,新Mat上的修改不会影响旧的。

I find the source code of rowRange, there is some native code but clearly it creates a new object. 我找到了rowRange的源代码,有一些本机代码,但很明显它创建了一个新对象。

 public Mat rowRange(int startrow, int endrow)
 {

     Mat retVal = new Mat(n_rowRange(nativeObj, startrow, endrow));

     return retVal;
 }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM