تشغيل العديد من المخالفات في نفس الوقت - غير ممكن؟

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

لم يتم تنفيذ Asynctask الثاني. إذا قمت بتغيير ترتيب عبارات التنفيذ () ، فإن مهمة FOO فقط ستنتج الإخراج.

هل أفتقد شيئًا واضحًا هنا و/أو أفعل شيئًا غبيًا؟ أليس من الممكن تشغيل اثنين من المهاسين في نفس الوقت؟

تحرير: أدركت أن الهاتف المعني يعمل بنظام Android 1.5 ، لقد قمت بتحديث مشكلة DESCR. وفقاً لذلك. ليس لدي هذه المشكلة مع HTC Hero تشغيل Android 2.1. أمم ...

هل كانت مفيدة؟

المحلول

يستخدم Asynctask نمط تجمع الخيوط لتشغيل الأشياء من doinbackground (). المشكلة هي في البداية (في إصدارات نظام التشغيل Android المبكر) ، كان حجم التجمع 1 فقط ، مما يعني عدم وجود حسابات متوازية لمجموعة من المخالفات غير المتبادلة. لكن في وقت لاحق قاموا بإصلاح ذلك والآن الحجم هو 5 ، لذلك يمكن أن تعمل المخالفات المتزامنة على الأكثر في وقت واحد. لسوء الحظ ، لا أتذكر ما هو الإصدار الذي غير ذلك بالضبط.

تحديث:

إليك ما يقوله API الحالي (2012-01-27) عن هذا:

عند تقديمها لأول مرة ، تم تنفيذ المخالفات المتسلسلة بشكل تسلسلي على خيط خلفية واحد. بدءًا من الدونات ، تم تغيير هذا إلى مجموعة من الخيوط مما يسمح بمهام متعددة بالعمل بالتوازي. بعد قرص العسل ، من المخطط تغيير هذا مرة أخرى إلى مؤشر ترابط واحد لتجنب أخطاء التطبيق الشائعة الناتجة عن التنفيذ المتوازي. إذا كنت تريد حقًا تنفيذًا متوازيًا ، فيمكنك استخدام إصدار ExecuteOnexecutor (Executor ، Params ...) من هذه الطريقة باستخدام Thread_pool_executor ؛ ومع ذلك ، انظر التعليق هناك للحصول على تحذيرات بشأن استخدامها.

Donut هو Android 1.6 ، Honeycomb هو Android 3.0.

تحديث: 2

انظر التعليق من قبل kabuko من Mar 7 at 1:27.

اتضح أنه بالنسبة إلى واجهات برمجة التطبيقات حيث يتم استخدام "مجموعة من الخيوط التي تسمح بمهام متعددة بالعمل بالتوازي" (بدءًا من 1.6 وينتهي في 3.0) يعتمد عدد المخالفات المتزامنة في وقت واحد على عدد المهام التي تم تمريرها للتنفيذ بالفعل ، ولكن لم ينتهوا doInBackground() حتى الآن.

يتم اختبار هذا/تأكيده على 2.2. لنفترض أن لديك مسجلة غير متزامنة مخصصة تنام فقط في الثانية doInBackground(). تستخدم المخالفات المتزامنة قائمة انتظار ثابتة بحجم داخلي لتخزين المهام المتأخرة. حجم قائمة الانتظار هو 10 بشكل افتراضي. إذا بدأت 15 مهامك المخصصة على التوالي ، فستدخل First 5 doInBackground(), ، لكن الباقي سينتظر في قائمة انتظار لخيط عامل مجاني. بمجرد أن ينتهي أي من أول 5 سنوات ، وبالتالي تطلق خيط العمال ، ستبدأ مهمة من قائمة الانتظار في التنفيذ. لذلك في هذه الحالة على الأكثر 5 مهام سيتم تشغيلها في وقت واحد. ومع ذلك ، إذا بدأت 16 مهامك المخصصة على التوالي ، فستدخل First 5 doInBackground(), ، سوف يدخل الباقي 10 في قائمة الانتظار ، ولكن سيتم إنشاء مؤشر ترابط عامل جديد في السادس عشر بحيث يبدأ التنفيذ على الفور. لذلك في هذه الحالة على الأكثر 6 مهام سيتم تشغيلها في وقت واحد.

هناك حد لعدد المهام التي يمكن تشغيلها في وقت واحد. حيث AsyncTask يستخدم Executor Pool Pool مع عدد أقصى محدود من مؤشرات ترابط العمال (128) ، كما أن قائمة انتظار المهام المتأخرة تحتوي على حجم 10 ، إذا حاولت تنفيذ أكثر من 138 مهمة مخصصة ستعطل التطبيق مع java.util.concurrent.RejectedExecutionException.

بدءًا من 3.0 ، يسمح API باستخدام Executor Pool Custom Thread عبر 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_asynctask

تحديث: 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 عنصرًا ويقلل من الحد الأقصى لعدد مؤشرات الترابط إلى عدد نوى وحدة المعالجة المركزية * 2 + 1. لا يزال بإمكان التطبيقات تقديم نفس عدد المهام.

نصائح أخرى

هذا يسمح بالتنفيذ الموازي على جميع إصدارات 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);
}

هذا ملخص لإجابة Arhimed الممتازة.

يرجى التأكد من استخدام مستوى API 11 أو أعلى كهدف لبناء المشروع. في Eclipse ، هذا هو Project > Properties > Android > Project Build Target. هذا سوف ليس كسر التوافق الخلفي لخفض مستويات API. لا تقلق ، ستحصل على أخطاء في الوبر إذا استخدمت الميزات التي تم تقديمها بطريق الخطأ في وقت لاحق من 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 لتحميل Bitmaps بكفاءة مسجلة Asynctask مخصصة (منسوخة من Jellybean) حتى تتمكن من استخدام ExecuteOnexecutor في واجهات برمجة التطبيقات أقل من <11

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

قم بتنزيل الرمز وانتقل إلى حزمة Util.

إنه أمر ممكن. إصدار جهاز 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();

هذا يعمل تماما. واحد تلو الآخر محملة المغازل الخاصة بي. لم أقم بإعداد المستخدم executeOnexecutor.

ها هو صفي في المهام غير المتزامنة

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") بعد إصدار Android من 3.0 ؛ ولكن هذه الطريقة غير موجودة قبل Android 3.0 وبعد 1.6 لأنها تنفذ بالتوازي بنفسها ، لذلك أقترح عليك تخصيص فئة Asynctask الخاصة بك في مشروعك ، لتجنب الاستثناء في إصدار Android مختلف.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top