AsyncTask的,它必须采取这样的表现加罚命中......? [英] AsyncTask, must it take such a performance penalty hit...?

查看:95
本文介绍了AsyncTask的,它必须采取这样的表现加罚命中......?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个小的应用程序,它读取特定的HTML页面,重新格式它们,然后显示他们在一个web视图。如果我跑我的code在GUI线程,性能损失接近忽略不计相比,简单地让web视图显示原始的HTML页面。但是,如果我是一个好男孩,不喜欢有人告诉我,我应该使用的AsyncTask运行code的背景,以免那些3-5秒我$期间冻结了图形用户界面C $Ç它的工作。问题是,如果我这样做,code作为需要长时间才能完成的10倍以上。一个页面需要60多秒的节目,这是不可接受的。

I'm developing a small app that reads in specific html-pages, re-formats them and then shows them in a WebView. If I run my code in the GUI thread, the performance hit is close to negligible compared to simply letting the WebView show the original html-page. But if I'm a good boy and do like I'm told, I'm supposed to use an AsyncTask to run the code in the background so as not to freeze up the GUI during those 3-5 seconds my code does its job. Problem is... if I do so, the code takes more than 10 times as long to finish. A page takes 60+ seconds to show, which is unacceptable.

跟踪问题,TraceView让我发现,我的AsyncTask是(在默认优先级)运行在大约10毫秒块,周围每秒4次。我需要设置我的线程优先MAX_PRIORITY亲近到可以接受的加载时间,但即使如此,它花费的时间比我在GUI线程中运行3-4倍。

Tracking down the problem, TraceView shows me that my AsyncTask is (at default priority) run in roughly 10 ms chunks, around 4 times per second. I need to set my thread priority to MAX_PRIORITY to get close to acceptable loading times, but even then it takes 3-4 times longer than when I run in the GUI thread.

我是不是做错了什么,或者这只是它的工作方式?而且必须将它以这种方式工作...?

Am I doing something wrong, or is this just the way it works? And must it work this way...?

下面是按要求编译code:

Here's compilable code as requested:

package my.ownpackage.athome;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.StrictMode;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class AndroidTestActivity extends Activity
{   
    WebView webview;
    //...

    private class HelloWebViewClient extends WebViewClient 
    {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) 
        {
            AndroidTestActivity.this.fetch(view, url);
            return true;
        }
    }

    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // To allow to connect to the web and pull down html-files, reset strict mode
        // see http://stackoverflow.com/questions/8706464/defaulthttpclient-to-androidhttpclient
        if (android.os.Build.VERSION.SDK_INT > 9) 
        {
            StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
            StrictMode.setThreadPolicy(policy);
        }

        // webview init etc...

        fetch(webview, "http://www.example.com");   
    }

    // This one calls either the AsyncTask or does it all manually in the GUI thread
    public void fetch(WebView view, String url)
    {
        //** Use these when run as AsyncTask in background - SLOW! 
        //** Takes 30+ seconds at default thread priority, with MAX_PRIORITY 15+ seconds
        // AsyncTask<Void, String, String> fx = new FilterX(url, view, this);   
        // fx.execute();    // running as AsyncTask takes roughly ten times longer than just plain load!    

        //** Use these when not running as AsyncTask - FAST! takes ~5 seconds
        FilterX fx = new FilterX(url, view, this);
        fx.onPreExecute();
        final String str = fx.doInBackground();
        fx.onPostExecute(str);
    }
}

class FilterX extends AsyncTask<Void, String, String>
{
    WebView the_view = null;
    // other stuff...

    FilterX(final String url, final WebView view, final Activity activity)
    {
        the_view = view;
        // other initialization
        // same code in both cases
    }

    protected void onPreExecute()
    {
        // same code in both cases
    }

    protected String doInBackground(Void... v)
    {
        // same in both cases...

        return new String();    // just to make it compile
    }

    protected void onPostExecute(final String string)
    {
        the_view.loadUrl(string);
        // same in both cases...
    }
}

要运行的完全当为的AsyncTask的GUI线程上运行时,运行相同的code在我FilterX课,我删除所有进度东西,然后我得到以下时序:

To run exactly the same code in my FilterX class when run as AsyncTask as when run on the GUI thread, I stripped all ProgressBar stuff, and then I get the following timings:

  • 30+秒到默认的线程优先级加载一个页面
  • 15+秒以MAX_PRIORITY加载一个页面
  • 在至少5秒钟,在GUI线程中运行时加载一个页面

推荐答案

您是不是唯一一个观察这种行为。通过10倍的增长放缓可能是Android系统使用的是Linux的cgroup(调度类)进行优先级背景或低于线程的结果。所有这些线程必须忍受10%的CPU时间完全。

You're not the only one observing this behaviour. The slowdown by factor 10 is probably a result of Android using a Linux cgroup (scheduling class) for threads of priority BACKGROUND or below. All these threads have to live with 10% CPU time altogether.

好消息是,你不必忍受来自java.lang.Thread的线程优先级设置。您可以从android.os.Process定义你的分配一个线程的pthread(Linux的线程)的优先级。在那里,你不仅有Process.THREAD_PRIORITY_BACKGROUND,也常来调整优先级位。

The good news is you don't have to live with the Thread priority settings from java.lang.Thread. You can assign your Thread a pthread (Linux thread) priority from the definitions in android.os.Process. There, you not only have Process.THREAD_PRIORITY_BACKGROUND, but also constants to adjust the priority a bit.

目前,Android使用后台线程cgroup中的优先级THREAD_PRIORITY_BACKGROUND或更糟的所有线程,并THREAD_PRIORITY_BACKGROUND是10,而THREAD_PRIORITY_DEFAULT为0,THREAD_PRIORITY_FOREGROUND是-2。

Currently, Android uses the background thread cgroup for all threads with priority THREAD_PRIORITY_BACKGROUND or worse, and THREAD_PRIORITY_BACKGROUND is 10 while THREAD_PRIORITY_DEFAULT is 0 and THREAD_PRIORITY_FOREGROUND is -2.

如果你去THREAD_PRIORITY_BACKGROUND + THREAD_PRIORITY_MORE_FAVORABLE(又名9)你的线程将被解除了背景cgroup中的10%的限制,而不是重要的,足以打断你的用户界面线程太多。

If you go for THREAD_PRIORITY_BACKGROUND + THREAD_PRIORITY_MORE_FAVORABLE (aka 9) your thread will be lifted out of the background cgroup with the 10% limitation, while not being important enough to interrupt your User Interface threads too often.

我相信,有哪些需要一些计算能力,但它们在阻止用户界面(通过消耗过多的CPU在单独的线程),同时还不足以事实上的重要和Android目前还没有明显的优先级的后台任务分配到这些,所以在我看来,这是可以分配给这样的任务最好的工作重点之一。

I believe there are background tasks which need a bit of computational power but which are at the same time not important enough to de facto block the UI (by consuming too much CPU in a separate thread) and Android currently has no obvious priority to assign to these, so in my view, this is one of the best priorities you can assign to such a task.

如果你可以用一个HandlerThread很容易实现的:

If you can use a HandlerThread it's easy to achieve:

ht = new HandlerThread("thread name", THREAD_PRIORITY_BACKGROUND + THREAD_PRIORITY_MORE_FAVORABLE);
ht.start();
h  = new Handler(ht.getLooper()); 

如果你想要去的AsyncTask,你仍然可以做

If you want to go with AsyncTask, you can still do

protected final YourResult doInBackground(YourInputs... yis) {
    Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND + THREAD_PRIORITY_MORE_FAVORABLE);
    ...
}

但要注意,底层的实现可以重复使用于不同的任务相同的线程对象,在接下来的AsyncTask,或什么的。如此看来,Android的简单重置优先级后doInBackground()返回,虽然。

but be aware that the underlying implementation may reuse the same Thread object for different tasks, for the next AsyncTask, or whatever. It seems that Android simply resets the priority after doInBackground() returns, though.

当然,如果你的UI确实消耗CPU和你想为你的任务的同时更省电,把它离用户界面,可以设置另一个优先事项,也许多达Process.THREAD_PRIORITY_FOREGROUND。

Of course, if your UI really consumes CPU and you want more power for your task at the same time, taking it away from the UI, you can set another priority, maybe up to Process.THREAD_PRIORITY_FOREGROUND.

这篇关于AsyncTask的,它必须采取这样的表现加罚命中......?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆