অ্যান্ড্রয়েড অ্যাসিঙ্কটাস্ক থ্রেডস সীমাবদ্ধ?


95

আমি এমন একটি অ্যাপ্লিকেশন বিকাশ করছি যেখানে প্রতিবার ব্যবহারকারীরা সিস্টেমে লগ ইন করে আমাকে কিছু তথ্য আপডেট করতে হবে, আমি ফোনে ডাটাবেসও ব্যবহার করি। এই সমস্ত অপারেশনের জন্য (আপডেট, ডিবি থেকে ডেটা পুনরুদ্ধার এবং ইত্যাদি) আমি অ্যাসিঙ্ক টাস্ক ব্যবহার করি। এখনও অবধি আমি দেখতে পেলাম না কেন আমি সেগুলি ব্যবহার করব না, তবে সম্প্রতি আমি অভিজ্ঞ হয়েছি যে আমি যদি কিছু অপারেশন করি তবে আমার কিছু অ্যাসিঙ্ক কাজ কেবল প্রাক-এক্সিকিউটিভের উপর থামায় এবং ডিনব্যাকগ্রাউন্ডে ঝাঁপ না দিয়ে। এটি এটিকে ছেড়ে যাওয়া খুব অদ্ভুত ছিল, তাই আমি কী ভুল তা খতিয়ে দেখার জন্য আরও একটি সহজ অ্যাপ্লিকেশন বিকাশ করেছি। এবং যথেষ্ট আশ্চর্যের বিষয়, যখন মোট অ্যাসিঙ্ক কার্যগুলি গণনা 5-এ পৌঁছে যায় তখন behavior ষ্ঠটি প্রাক-এক্সিকিউটিভ বন্ধ করে দেয় I

অ্যান্ড্রয়েডের কার্যকলাপ / অ্যাপে অ্যাসিঙ্কটাস্কের সীমাবদ্ধতা রয়েছে? বা এটি কি কিছু বাগ এবং এটি রিপোর্ট করা উচিত? কেউ কি একই সমস্যাটি অনুভব করেছেন এবং সম্ভবত এটির জন্য একটি সমাধান খুঁজে পেয়েছেন?

কোডটি এখানে:

ব্যাকগ্রাউন্ডে কাজ করার জন্য কেবল এই থ্রেডগুলির মধ্যে 5 তৈরি করুন:

private class LongAsync extends AsyncTask<String, Void, String>
{
    @Override
    protected void onPreExecute()
    {
        Log.d("TestBug","onPreExecute");
        isRunning = true;
    }

    @Override
    protected String doInBackground(String... params)
    {
        Log.d("TestBug","doInBackground");
        while (isRunning)
        {

        }
        return null;
    }

    @Override
    protected void onPostExecute(String result)
    {
        Log.d("TestBug","onPostExecute");
    }
}

এবং তারপরে এই থ্রেডটি তৈরি করুন। এটি প্রি এক্সেকিউট প্রবেশ করবে এবং স্তব্ধ হয়ে যাবে (এটি doInBackground এ যাবে না)।

private class TestBug extends AsyncTask<String, Void, String>
{
    @Override
    protected void onPreExecute()
    {
        Log.d("TestBug","onPreExecute");

        waiting = new ProgressDialog(TestActivity.this);
        waiting.setMessage("Loading data");
        waiting.setIndeterminate(true);
        waiting.setCancelable(true);
        waiting.show();
    }

    @Override
    protected String doInBackground(String... params)
    {
        Log.d("TestBug","doInBackground");
        return null;
    }

    @Override
    protected void onPostExecute(String result)
    {
        waiting.cancel();
        Log.d("TestBug","onPostExecute");
    }
}

উত্তর:


207

সমস্ত অ্যাসিঙ্কটাস্কগুলি ভাগ করে নেওয়া (স্ট্যাটিক) থ্রেডপুলএক্সেকিউটার এবং একটি লিংকডব্লকিংকিউ দ্বারা অভ্যন্তরীণভাবে নিয়ন্ত্রণ করা হয় । আপনি যখন executeঅ্যাসিঙ্কটাস্কে কল করবেন, ThreadPoolExecutorভবিষ্যতে কিছু সময় প্রস্তুত হয়ে গেলে এটি কার্যকর করবে the

'আমি কখন প্রস্তুত?' এর আচরণ ThreadPoolExecutorদুটি পরামিতি, মূল পুলের আকার এবং সর্বাধিক পুলের আকার দ্বারা নিয়ন্ত্রিত হয় । বর্তমানে যদি পুলের চেয়ে কম আকারের থ্রেডগুলি সক্রিয় থাকে এবং একটি নতুন কাজ আসে তবে এক্সিকিউটার একটি নতুন থ্রেড তৈরি করে তাৎক্ষণিকভাবে সম্পাদন করবে। যদি কমপক্ষে মূল পুলের আকারের থ্রেডগুলি চলমান থাকে তবে এটি কাজটি সারি করার চেষ্টা করবে এবং অলস থ্রেড উপলব্ধ না হওয়া পর্যন্ত অপেক্ষা করবে (অন্য কোনও কাজ শেষ না হওয়া পর্যন্ত)। যদি কাজটি সারি করা সম্ভব না হয় (সারিটির সর্বাধিক ক্ষমতা থাকতে পারে), এটি কাজগুলি চালানোর জন্য একটি নতুন থ্রেড তৈরি করবে (সর্বোচ্চ স্তরের আকারের থ্রেড) তৈরি করবে Non একটি বেঁচে থাকার সময়সীমা পরামিতি অনুসারে।

অ্যান্ড্রয়েড ১.6 এর আগে কোর পুলের আকার 1 এবং সর্বোচ্চ পুলের আকার ছিল 10. অ্যান্ড্রয়েড 1.6 যেহেতু, মূল পুলের আকার 5, এবং সর্বাধিক পুলের আকার 128 both উভয় ক্ষেত্রেই সারির আকার 10 হয়। এই লাইফ-লাইভ টাইমআউটটি 2.3 এর আগে 10 সেকেন্ড ছিল এবং তখন থেকে 1 সেকেন্ড।

এই সমস্ত কিছু মনে রেখে, এখন এটি স্পষ্ট হয়ে যায় যে কেন AsyncTaskকেবলমাত্র আপনার কাজগুলির 5/6 কার্য সম্পাদন করতে দেখা যাবে। অন্য একটির কাজ শেষ না হওয়া পর্যন্ত tasks ষ্ঠ টাস্কটি সারিবদ্ধ করা হচ্ছে। এটি দীর্ঘকাল ধরে চলমান ক্রিয়াকলাপগুলির জন্য আপনাকে AsyncTasks ব্যবহার না করা কেন এটি খুব ভাল কারণ - এটি অন্যান্য AsyncTasks কে কখনও চলমান থেকে বাধা দেবে।

সম্পূর্ণতার জন্য, যদি আপনি 6 টিরও বেশি কাজের (যেমন 30) আপনার অনুশীলনটির পুনরাবৃত্তি করেন তবে আপনি দেখতে পাবেন যে doInBackgroundসারিটি পূর্ণ হয়ে যাওয়ার সাথে সাথে 6 টিরও বেশি প্রবেশ করবে এবং এক্সিকিউটার আরও কর্মী থ্রেড তৈরি করতে বাধ্য হবে। আপনি যদি দীর্ঘ-চলমান কাজটি চালিয়ে যান, আপনার দেখতে হবে যে 20/30 সক্রিয় রয়েছে, 10 টি এখনও সারিতে রয়েছে।


4
"দীর্ঘকাল ধরে চলমান ক্রিয়াকলাপগুলির জন্য আপনাকে এসিঙ্কটাস্ক ব্যবহার করা উচিত নয় এটি একটি খুব ভাল কারণ" এই দৃশ্যের জন্য আপনার সুপারিশ কী? ম্যানুয়ালি একটি নতুন থ্রেড তৈরি করছেন বা আপনার নিজস্ব নির্বাহক পরিষেবা তৈরি করছেন?
ব্যবহারকারী 123321

4
এক্সিকিউটাররা মূলত থ্রেডগুলির শীর্ষে একটি বিমূর্ততা, এগুলি পরিচালনা করার জন্য জটিল কোড লেখার প্রয়োজনীয়তা হ্রাস করে। এটি আপনার কার্যগুলি কীভাবে সম্পাদন করা উচিত তা থেকে ডিকোপল করে। যদি আপনার কোডটি কেবলমাত্র একজন নির্বাহকের উপর নির্ভর করে তবে কয়টি থ্রেড ব্যবহার করা হয়েছে তা স্বচ্ছভাবে পরিবর্তন করা সহজ etc. ইত্যাদি I আমি নিজেই থ্রেড তৈরির কোনও ভাল কারণ সম্পর্কে সত্যিই ভাবতে পারি না, এমনকি সাধারণ কাজের জন্যও যে পরিমাণের কাজ করে এক্সিকিউটার একই, যদি কম না হয়।
অ্যান্টিনিট

37
অনুগ্রহ করে নোট করুন যে অ্যান্ড্রয়েড +.০+ থেকে, সমকালীন অ্যাসিঙ্কটাস্কের ডিফল্ট সংখ্যাটি হ্রাস করা হয়েছে ১ এ। আরও তথ্য: ডেভেলপার.অ্যান্ড্রয়েড.
কিরান

বাহ, একটি দুর্দান্ত উত্তরের জন্য অনেক ধন্যবাদ। পরিশেষে আমার ব্যাখ্যা রয়েছে যে আমার কোডটি কেন বিক্ষিপ্তভাবে এবং রহস্যজনকভাবে ব্যর্থ হচ্ছে।
ক্রিস নাইট

@ এন্টনিট, আরও সন্দেহ, বাতিল হওয়া অ্যাসিঙ্কটাস্কস, এটি কি অ্যাসিঙ্কটাস্কের সংখ্যায় গণনা করবে? অর্থাৎ, গণনা করা হয় core pool sizeবা maximum pool size?
এনএম এক্সপ্রিম

9

@ এন্টনিটের সঠিক উত্তর রয়েছে তবে আপনি যদি সহজ সমাধানের সন্ধান করছেন তবে আপনি সুইটি পরীক্ষা করে দেখতে পারেন।

এটির সাহায্যে আপনি একটি কাস্টম থ্রেড পুলের আকার নির্ধারণ করতে পারেন এবং এর বিপরীতে AsyncTask, এটি সমস্ত অ্যান্ড্রয়েড সংস্করণে একই কাজ করে । এটির সাহায্যে আপনি এ জাতীয় কথা বলতে পারেন:

Needle.onBackgroundThread().withThreadPoolSize(3).execute(new UiRelatedTask<Integer>() {
   @Override
   protected Integer doWork() {
       int result = 1+2;
       return result;
   }

   @Override
   protected void thenDoUiRelatedWork(Integer result) {
       mSomeTextView.setText("result: " + result);
   }
});

বা ভালো জিনিস

Needle.onMainThread().execute(new Runnable() {
   @Override
   public void run() {
       // e.g. change one of the views
   }
}); 

এটি আরও অনেক কিছু করতে পারে। এটি গিটহাবে পরীক্ষা করে দেখুন ।


শেষ প্রতিশ্রুতি 5 বছর আগে ছিল :(
লুকাশজটারাস্কা

5

আপডেট : API 19 19 সাল থেকে মূল থ্রেড পুলের আকারটি সিপিইউ * 2 +1 সর্বাধিক বাড়তে গিয়ে শুরুতে সর্বনিম্ন 2 এবং সর্বোচ্চ 4 দিয়ে ডিভাইসে সিপিইউগুলির সংখ্যা প্রতিবিম্বিত করতে পরিবর্তন করা হয়েছিল - রেফারেন্স

// We want at least 2 threads and at most 4 threads in the core pool,
// preferring to have 1 less than the CPU count to avoid saturating
// the CPU with background work
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;

এছাড়াও মনে রাখবেন যখন AsyncTask ডিফল্ট নির্বাহক সিরিয়াল (, executes একটি সময়ে শৃঙ্খলা যা তারা পৌঁছা এক কাজের), সঙ্গে পদ্ধতি

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
        Params... params)

আপনি আপনার কাজগুলি চালানোর জন্য একজন নির্বাহককে সরবরাহ করতে পারেন। আপনি THREAD_POOL_EXECUTOR কে হুড এক্সিকিউটারের অধীনে সরবরাহ করতে পারেন তবে কোনও ক্রমিক ক্রিয়াকলাপ ছাড়াই বা আপনি নিজের এক্সিকিউটর তৈরি করে এখানে সরবরাহ করতে পারেন। তবে জাভাদোকসে সতর্কতার সাথে সাবধানে নোট করুন।

সতর্কতা: একাধিক কাজকে থ্রেড পুল থেকে সমান্তরালভাবে চালাতে দেওয়া সাধারণত যা চায় তা নয়, কারণ তাদের ক্রিয়াকলাপের ক্রম সংজ্ঞায়িত করা হয়নি। উদাহরণস্বরূপ, যদি এই কাজগুলি কোনও রাজ্যে সাধারণভাবে সংশোধন করতে ব্যবহৃত হয় (যেমন একটি বোতাম ক্লিকের কারণে কোনও ফাইল লেখার জন্য), পরিবর্তনের ক্রমের কোনও গ্যারান্টি নেই। সতর্কতার সাথে কাজ করা ব্যতিরেকে ক্ষেত্রে কোনও ডেটার নতুন সংস্করণটি কোনও পুরানো ব্যক্তির দ্বারা অতিরিক্ত-রচনা করা সম্ভব হয়, যা তথ্যকে অস্পষ্ট করে তোলে এবং স্থিতিশীলতার সমস্যা দেখা দেয়। এই ধরনের পরিবর্তনগুলি সিরিয়ালে সেরা সম্পাদন করা হয়; প্ল্যাটফর্ম সংস্করণ নির্বিশেষে এ জাতীয় কাজটি সিরিয়ালাইজড গ্যারান্টি হিসাবে আপনি এই ক্রিয়াকলাপটি SERIAL_EXECUTOR এর সাথে ব্যবহার করতে পারেন।

আরও একটি বিষয় লক্ষণীয় হ'ল উভয় কাঠামো এক্সিকিউটরগণ THREAD_POOL_EXECUTOR সরবরাহ করেছে এবং এর সিরিয়াল সংস্করণ SERIAL_EXECUTOR (যা AsyncTask এর জন্য ডিফল্ট) স্ট্যাটিক (শ্রেণির স্তরের গঠন) এবং তাই আপনার অ্যাপ্লিকেশন প্রক্রিয়া জুড়ে AsyncTask (গুলি) এর সমস্ত উদাহরণ জুড়ে ভাগ করা হয়েছে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.