【问题标题】:Unable to get performance benefit from ThreadPoolExecutor无法从 ThreadPoolExecutor 获得性能优势
【发布时间】:2019-03-14 01:46:53
【问题描述】:

我正在使用 ThreadPoolExecutor 下载大量图像。 android 应用在 10mbps 连接下的性能非常出色,通常优于在 iPad 上下载类似数据的结果。

但是,当我在更快的互联网连接 (60mbps) 上运行相同的应用程序时,android 应用程序无法更快地同步(需要 6 分钟),而 iPad 会在一分钟内下载所有内容。

我已经对任一连接上的两个设备进行了速度检查,得到了相同的结果,这意味着垫没有问题。为了避免任何外部应用程序导致问题,我将设备恢复出厂设置,尝试使用 Picasso、BitmapFactory 等优化图像下载,但没有成功。

我有三星 Galaxy Tab S2(T173) 八核和 3GB RAM 和 iPad Air。

这是与android平台的处理器限制有关还是我在开发端遗漏了什么,请帮助...提前谢谢。

这就是我使用 ThreadPoolExecutor 的方式。

int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
executor = new ThreadPoolExecutor(
               NUMBER_OF_CORES * 2,
               NUMBER_OF_CORES * 2,
               60L,
               TimeUnit.SECONDS,
               new LinkedBlockingQueue<Runnable>()
          );
 executor.allowCoreThreadTimeOut(true);

 for (int i = 0; i < totalCount; i++) {
                 executor.execute(new ImageDownloader(context, i, new Handler(), imageUrl, diagram_names.get(i), null));
            }

这是 ImageDownloader 类:

public class ImageDownloader implements Runnable {
int threadNo;
Handler handler;
String imageUrl;
public static final String TAG = "Image Downloader";
String imageName, calledFrom;
Activity applicationContext;
public ImageDownloader() {

}

public ImageDownloader(Activity applicationContext, int threadNo, Handler handler, String imageUrl, String imageName, String calledFrom) {
    this.applicationContext = applicationContext;
    this.threadNo = threadNo;
    this.handler = handler;
    this.imageUrl = imageUrl;
    this.imageName = imageName;
    this.calledFrom = calledFrom;
}

@Override
public void run() {
        if(CommonMethods.isNetworkAvailable(applicationContext))
            getBitmap(imageUrl, imageName);
}

private Bitmap getBitmap(String url, String imageName) {
    Bitmap bitmap = null;
    try {
        saveImage(Picasso.with(applicationContext).load(url).get(), imageName, url);
    } catch (Exception e) {
        e.printStackTrace();
    }

    return bitmap;
}

private void saveImage(Bitmap bmImg, String name) {
    if (bmImg != null) {
        try {
            File myDir = new File(Environment.getExternalStorageDirectory()
                    .toString() + "/AppReader/saved_signature");

            // make the directory if it does not exist yet
            if (!myDir.exists()) {
                myDir.mkdirs();
            }

            try {
                FileOutputStream out = new FileOutputStream(file);
                Log.i("in save()", "after outputstream");
                DisplayMetrics displayMetrics = applicationContext.getResources().getDisplayMetrics();
                int width = displayMetrics.widthPixels;
                int height = displayMetrics.heightPixels;
                Bitmap resizedBitmap = bmImg;
                resizedBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
                out.flush();
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
}

【问题讨论】:

  • 您可能在开发端遗漏了一些东西。但除非您可以向我们展示您的代码的相关部分,否则我们只能猜测可能是什么。
  • @StephenC:我已经用相关代码信息更新了我的问题。请提出建议。

标签: android multithreading image performance threadpoolexecutor


【解决方案1】:

我建议你做一些优化 - 例如使用例如java.util.concurrent.Executors.newCachedThreadPool() - 这又是 ThreadPoolExecutor,但配置不同 - 请参阅 doc https://developer.android.com/reference/java/util/concurrent/Executors.html#newCachedThreadPool() 了解更多信息

同样在您上面的代码中,您似乎总是尝试写入同一个文件(saveImage 中未使用名称参数),这绝对不行,因为它会阻塞,但我想这只是复制/粘贴错误。

如果你移动“init”代码也没有什么坏处——检查目录是否存在、displayMetrics等到代码的其他部分,所以它们不会在每个线程上执行。

然后,您还可以检查限制因素是否不是 getExternalStorageDirectory() 指向您设备上的任何内容的写入速度 - 例如您的网络可能非常快,但如果您的存储速度很慢...

【讨论】:

  • 使用 Executors.newCachedThreadPool() 一次生成所有线程。因此,我收到 OKHTTP 错误,说一次打开的文件太多,某些线程也被阻止,有些被拒绝。这也会冻结应用程序并需要终止应用程序。我可以在 newCachedThreadPool() 中返回自定义线程池,但它的工作方式与我最初的工作方式相同。请提出建议。
  • 尝试了其他改进建议,没有发现任何显着差异,但确实改进了代码。在这里写入外部磁盘似乎也不是问题。请提出建议。
  • 哦,你正试图同时下载那么多文件......好吧,那么你肯定可以将池限制在一个更可接受的值 - 或者......如果你想匹配/超过您的 iPad 性能 - 检查它同时打开了多少个连接并执行相同或更多操作(+1?)
  • 是的,这就是我一直在做的事情..但无法从中获得性能。我将更多地尝试线程池。如果您找到任何解决方案,请提出建议。
猜你喜欢
  • 1970-01-01
  • 2010-10-20
  • 2011-03-21
  • 2013-05-29
  • 1970-01-01
  • 2015-01-06
  • 2021-06-14
  • 1970-01-01
  • 2017-05-29
相关资源
最近更新 更多