Бег нескольких асинктюзников одновременно - невозможно?

StackOverflow https://stackoverflow.com/questions/4068984

Вопрос

Я пытаюсь запустить две асинктюды одновременно. (Платформа - это Android 1.5, HTC Hero.) Однако только первый выполняется. Вот простой фрагмент, чтобы описать мою проблему:

public class AndroidJunk extends Activity {
 class PrinterTask extends AsyncTask<String, Void, Void> {
     protected Void doInBackground(String ... x) {
      while (true) {
       System.out.println(x[0]);
       try {
        Thread.sleep(1000);
       } catch (InterruptedException ie) {
        ie.printStackTrace();
       }
      }
        }
    };

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

        new PrinterTask().execute("bar bar bar");
        new PrinterTask().execute("foo foo foo");

        System.out.println("onCreate() is done.");
    }
}

Выход я ожидаю:

onCreate() is done.
bar bar bar
foo foo foo
bar bar bar
foo foo foo

И так далее. Тем не менее, то, что я получаю:

onCreate() is done.
bar bar bar
bar bar bar
bar bar bar

Вторая асинктка никогда не выполняется. Если я изменю порядок операторов EXECUTE (), только задача FOO будет производить вывод.

Я упускаю что-то очевидное здесь и / или делать что-то глупое? Разве невозможно запустить две асинктюды одновременно?

Редактировать: Я понял, что телефон в вопросе работает Android 1.5, я обновил проблему. соответственно. У меня нет этой проблемы с HTC Hero работает Android 2.1. Хм ...

Это было полезно?

Решение

Asynctask использует шаблон пула резьбы для запуска материала из DOINBACKGLE (). Проблема изначально (в ранних версиях Android ОС) размером бассейна было всего 1, что означает отсутствие параллельных вычислений для кучка асинкт-дисплеев. Но позже они исправили это, и теперь размер 5, поэтому у большинства 5 асинктюз могут работать одновременно. К сожалению, я не помню в какую версию именно они изменили это.

ОБНОВИТЬ:

Вот какой текущий (2012-01-27) API говорит об этом:

При первом введенном, асинктюды были выполнены последовательно на одной фоновой нити. Начиная с пончика, это было изменено на пул потоков, позволяющих работать несколько задач параллельно. После соты планируется изменить это обратно в одну нить, чтобы избежать распространенных ошибок приложений, вызванных параллельным исполнением. Если вы действительно хотите выполнить параллельное исполнение, вы можете использовать версию этого метода ExecuteExuCuture (Исполнитель, Пармы ...) с Thread_pool_Executor; Однако см. Комментарий там для предупреждений о его использовании.

Пончик - это Android 1.6, сотами является Android 3.0.

Обновление: 2.

Смотрите комментарий kabuko от Mar 7 at 1:27.

Оказывается, для API, где используется «пул резьбы, позволяющих нескольким задачам работать параллельно» (начиная с 1,6 и заканчивая на 3.0) количество одновременно выполнения асинктюзскихs, зависит от того, сколько задач было передано для выполнения уже, но не закончили их doInBackground() все же.

Это проверено / подтверждено мной на 2.2. Предположим, у вас есть таможенная асинкт, которая просто спит второй в doInBackground(). Отказ Asynctasks используют очередь фиксированного размера внутренне для хранения задержки задач. Размер очереди 10 по умолчанию. Если вы начнете 15 ваших пользовательских задач подряд, то сначала 5 вступит в их doInBackground(), но остальные будут ждать в очереди для свободной рабочей нити. Как только любая из первых 5 отделок, и, таким образом, выпускает рабочая нить, задача из очереди начнется выполнение. Таким образом, в этом случае не более 5 задач будут работать одновременно. Однако, если вы начинаете 16 ваших пользовательских задач подряд, то сначала 5 вступит в их doInBackground(), остальные 10 попадут в очередь, но для 16-го новой рабочей нити будет создан, поэтому он немедленно начнет выполнение. Таким образом, в этом случае не более 6 задач будут работать одновременно.

Существует ограничение того, сколько задач можно запустить одновременно. С AsyncTask Использует Исполнитель пула резьбы с ограниченным максимальным количеством рабочих потоков (128) и очередь задержки задач имеет фиксированный размер 10, если вы попытаетесь выполнить более 138 ваших пользовательских задач, которые приложение разбито java.util.concurrent.RejectedExecutionException.

Начиная с 3.0 API позволяет использовать ваш исполнитель пула обычной резьбы через AsyncTask.executeOnExecutor(Executor exec, Params... params) метод. Это позволяет, например, для настройки размера задач очередей задач, если по умолчанию 10 не то, что вам нужно.

Как упоминает @knossos, есть возможность использовать возможность AsyncTaskCompat.executeParallel(task, params); От поддержки библиотеки V.4 для запуска задач параллельно без беспокойства с уровнем API. Этот метод устарел на уровне API 26.0.0.

Обновление: 3.

Вот простое тестовое приложение для воспроизведения с количеством задач, последовательными и параллельными исполнениями: https://github.com/vitkhudenko/test_asyncksk.

Обновление: 4. (Спасибо @Penkzhou за то, что указывал на это)

Начиная с Android 4.4 AsyncTask ведет себя по-разному от того, что было описано в Обновление: 2. раздел. Там это исправление предотвращать AsyncTask от создания слишком много потоков.

Перед Android 4.4 (API 19) AsyncTask имел следующие поля:

private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
        new LinkedBlockingQueue<Runnable>(10);

В Android 4.4 (API 19) Вышеуказанные поля изменяются на это:

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
        new LinkedBlockingQueue<Runnable>(128);

Это изменение увеличивает размер очереди до 128 элементов и уменьшает максимальное количество потоков к количеству CPU Cores * 2 + 1. Apps, которые все равно могут представить одинаковое количество задач.

Другие советы

Это позволяет для параллельного выполнения на всех версиях Android с API 4+ (Android 1.6+):

@TargetApi(Build.VERSION_CODES.HONEYCOMB) // API 11
void startMyTask(AsyncTask asyncTask) {
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
        asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
    else
        asyncTask.execute(params);
}

Это краткое изложение отличного ответа Архимеда.

Пожалуйста, убедитесь, что вы используете уровень API уровня 11 или выше, когда ваша цель сборки проекта. В затмении, то есть Project > Properties > Android > Project Build Target. Это будет нет нарушить обратную совместимость на более низкие уровни API. Не волнуйтесь, вы получите ошибки Lint, если ваши случайно используемые функции, представленные позже, чем minSdkVersion. Отказ Если вы действительно хотите использовать функции, представленные позже, чем minSdkVersion, вы можете подавить эти ошибки, используя аннотации, но в этом случае вам нужно позаботиться о совместимости сами. Отказ Это именно то, что произошло в фрагменте кода выше.

Сделать @sulai предложение более общего:

@TargetApi(Build.VERSION_CODES.HONEYCOMB) // API 11
public static <T> void executeAsyncTask(AsyncTask<T, ?, ?> asyncTask, T... params) {
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
        asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
    else
        asyncTask.execute(params);
}   

Просто чтобы включить последнее обновление (обновление 4) в непорочном ответе @arhimed в очень хорошем резюме @sulai:

void doTheTask(AsyncTask task) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { // Android 4.4 (API 19) and above
        // Parallel AsyncTasks are possible, with the thread-pool size dependent on device
        // hardware
        task.execute(params);
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { // Android 3.0 to
        // Android 4.3
        // Parallel AsyncTasks are not possible unless using executeOnExecutor
        task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
    } else { // Below Android 3.0
        // Parallel AsyncTasks are possible, with fixed thread-pool size
        task.execute(params);
    }
}

Пример разработки Android пример загрузки растровых изображений эффективно использует пользовательскую асинктюз (скопированную из Jellybean), чтобы вы могли использовать ExecuteExukuTor в API ниже, чем <11

http://developer.android.com/training/displaying-bitmaps/index.html.

Загрузите код и перейдите в Util Package.

Это возможно. Моя версия устройства Android - 4.0.4 и Android.Os.build.version.sdk_int 15

У меня есть 3 спина

Spinner c_fruit=(Spinner) findViewById(R.id.fruits);
Spinner c_vegetable=(Spinner) findViewById(R.id.vegetables);
Spinner c_beverage=(Spinner) findViewById(R.id.beverages);

А также у меня есть класс асинхронизации.

Вот мой спиннер загрузки

RequestSend reqs_fruit = new RequestSend(this);
reqs_fruit.where="Get_fruit_List";
reqs_fruit.title="Loading fruit";
reqs_fruit.execute();

RequestSend reqs_vegetable = new RequestSend(this);
reqs_vegetable.where="Get_vegetable_List";
reqs_vegetable.title="Loading vegetable";
reqs_vegetable.execute();

RequestSend reqs_beverage = new RequestSend(this);
reqs_beverage.where="Get_beverage_List";
reqs_beverage.title="Loading beverage";
reqs_beverage.execute();

Это работает отлично. Один за другим моими спиненами загружены. Я не пользователь ExecuteexuCutor.

Вот мой класс асинхронизации

public class RequestSend  extends AsyncTask<String, String, String > {

    private ProgressDialog dialog = null;
    public Spinner spin;
    public String where;
    public String title;
    Context con;
    Activity activity;      
    String[] items;

    public RequestSend(Context activityContext) {
        con = activityContext;
        dialog = new ProgressDialog(activityContext);
        this.activity = activityContext;
    }

    @Override
    protected void onPostExecute(String result) {
        try {
            ArrayAdapter<String> adapter = new ArrayAdapter<String> (activity, android.R.layout.simple_spinner_item, items);       
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
            spin.setAdapter(adapter);
        } catch (NullPointerException e) {
            Toast.makeText(activity, "Can not load list. Check your connection", Toast.LENGTH_LONG).show();
            e.printStackTrace();
        } catch (Exception e)  {
            Toast.makeText(activity, "Can not load list. Check your connection", Toast.LENGTH_LONG).show();
            e.printStackTrace();
        }
        super.onPostExecute(result);

        if (dialog != null)
            dialog.dismiss();   
    }

    protected void onPreExecute() {
        super.onPreExecute();
        dialog.setTitle(title);
        dialog.setMessage("Wait...");
        dialog.setCancelable(false); 
        dialog.show();
    }

    @Override
    protected String doInBackground(String... Strings) {
        try {
            Send_Request();
            } catch (NullPointerException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        return null;
    }

    public void Send_Request() throws JSONException {

        try {
            String DataSendingTo = "http://www.example.com/AppRequest/" + where;
            //HttpClient
            HttpClient httpClient = new DefaultHttpClient();
            //Post header
            HttpPost httpPost = new HttpPost(DataSendingTo);
            //Adding data
            List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);

            nameValuePairs.add(new BasicNameValuePair("authorized","001"));

            httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
            // execute HTTP post request
            HttpResponse response = httpClient.execute(httpPost);

            BufferedReader reader;
            try {
                reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
                StringBuilder builder = new StringBuilder();
                String line = null;
                while ((line = reader.readLine()) != null) {
                    builder.append(line) ;
                }

                JSONTokener tokener = new JSONTokener(builder.toString());
                JSONArray finalResult = new JSONArray(tokener);
                items = new String[finalResult.length()]; 
                // looping through All details and store in public String array
                for(int i = 0; i < finalResult.length(); i++) {
                    JSONObject c = finalResult.getJSONObject(i);
                    items[i]=c.getString("data_name");
                }

            } catch (ClientProtocolException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Если вы хотите выполнить задачи параллельно, вам нужно позвонить по методу executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "your task name") После андроидной версии 3.0; Но этот метод не существует до Android 3.0 и после 1.6, потому что он выполняется параллельно сам по себе, поэтому я предлагаю настроить свой собственный класс Asyncctask в вашем проекте, чтобы избежать исключения в разных андроидах.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top