আইফোন - গ্র্যান্ড সেন্ট্রাল প্রেরণ মূল থ্রেড


145

আমি আমার অ্যাপ্লিকেশনগুলিতে সাফল্য, গ্র্যান্ড সেন্ট্রাল প্রেরণে ব্যবহার করছি, তবে আমি ভাবছিলাম যে এরকম কিছু ব্যবহারের আসল সুবিধা কী:

dispatch_async(dispatch_get_main_queue(), ^{ ... do stuff

অথবা এমনকি

dispatch_sync(dispatch_get_main_queue(), ^{ ... do stuff

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

[self doStuff];

ঠিক আছে?

আমি আপনাকে অবাক করে কি ভাবছি?


9
যাইহোক, প্রেরণ_সিন্যাসে একটি প্রধান সারি নিক্ষেপ করার ফলে অচলাবস্থার সৃষ্টি হবে।
ব্রুকস হেনেস

5
কেবল এটি ডক্সে পড়ুন: "প্রেরণ_কেন্দ্রের বিপরীতে, [প্রেরণ_মিলক] ব্লক শেষ না হওয়া পর্যন্ত ফিরে আসে না this বর্তমান সারিটি মূল থ্রেডের অর্থ নয়)। আমি ভুল হলে দয়া করে সংশোধন করুন।
ব্রুকস হেনেস

4
@ ব্রুকস হ্যানস সর্বদা সত্য নয়। আপনি ইতিমধ্যে মূল থ্রেডে থাকলে এটি একটি অচলাবস্থার ফলস্বরূপ । তা না হলে অচলাবস্থা থাকবে না। এখানে
হানি

উত্তর:


296

প্রধান কাতারে একটি ব্লক প্রেরণ করা সাধারণত একটি ব্যাকগ্রাউন্ড সারি থেকে কিছু পটভূমি প্রক্রিয়াকরণ সমাপ্ত হয়েছে যে সিগন্যাল করার জন্য সম্পন্ন হয় উদাহরণস্বরূপ

- (void)doCalculation
{
    //you can use any string instead "com.mycompany.myqueue"
    dispatch_queue_t backgroundQueue = dispatch_queue_create("com.mycompany.myqueue", 0);

    dispatch_async(backgroundQueue, ^{
        int result = <some really long calculation that takes seconds to complete>;

        dispatch_async(dispatch_get_main_queue(), ^{
            [self updateMyUIWithResult:result];
        });    
    });
}

এই ক্ষেত্রে, আমরা একটি ব্যাকগ্রাউন্ড সারিতে একটি দীর্ঘ গণনা করছি এবং যখন গণনাটি সম্পূর্ণ হবে তখন আমাদের ইউআই আপডেট করতে হবে। সাধারণত ইউআই আপডেট করার জন্য মূল সারিটি থেকে কাজ করতে হয় তাই আমরা দ্বিতীয় নেস্টেড ডিসপ্যাচ_সিএনসিএন ব্যবহার করে মূল কাতারে ফিরে 'সিগন্যাল' করি।

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

  • পটভূমি প্রক্রিয়াকরণ সমাপ্ত -> ইউআই আপডেট করুন
  • পটভূমি সারি -> সিগন্যাল প্রধান সারিতে পরবর্তী অংশ শুরু করার জন্য প্রক্রিয়াকৃত ডেটার অংশ
  • ব্যাকগ্রাউন্ড কাতারে আগত নেটওয়ার্ক ডেটা -> সিগন্যাল প্রধান সারিটি যে বার্তাটি এসেছে
  • ইত্যাদি

কেন আপনি প্রধান কাতারেটি থেকে প্রধান কাতারে প্রেরণ করতে চাইতে পারেন ... ঠিক আছে, আপনি সাধারণত এটি না করতেন তবে পরের বার রান লুপের জন্য কিছু কাজ করার সময় নির্ধারণ করার জন্য আপনি এটি করতে পারেন।


আহ আমি দেখি. তো, আমি ঠিকই বলেছি এটি করার কোনও সুবিধা নেই যদি আপনি ইতিমধ্যে মূল কাতারে থাকেন, কেবল যদি আপনি অন্য কাতারে থাকেন এবং ইউআই আপডেট করতে চান। ধন্যবাদ।
হাঁস

মূল সারি থেকে এটি করা কেন খুব কার্যকর নয় তা নিয়ে কথা বলতে আমার উত্তর সম্পাদনা করেছেন ited
রবিন সামারহিল

এছাড়াও, আমি মনে করি আইওএস 4 এ একটি বাগ আছে (আইওএস 5 এ চলে যেতে পারে), যেখানে মূল থ্রেড থেকে মূল সারিটিতে প্রেরণ_সিন্যাস কেবল একটি হ্যাংয়ের কারণ হয়ে থাকে, তাই আমি এটি পুরোপুরি করা এড়াতে চাই।
joerick

10
এটি কোনও বাগ নয়, এটি প্রত্যাশিত আচরণ। স্বীকৃতভাবে খুব কার্যকর আচরণ নয় তবে dispatch_sync ব্যবহার করার সময় আপনার সর্বদা ডেডলক সম্পর্কে সচেতন হওয়া দরকার। আপনি আশা করতে পারবেন না যে সিস্টেম আপনাকে সর্বদা প্রোগ্রামার ত্রুটি থেকে রক্ষা করবে।
রবিন সামারহিল

2
এখানে ব্যাকগ্রাউন্ড কিউ? আমি কীভাবে ব্যাকগ্রাউন্ড
কিউ

16

প্রধান থ্রেড থেকে মূল কাতারে ব্লক প্রেরণ দরকারী হতে পারে। এটি মূল কাতারে সারি করা অন্যান্য ব্লকগুলি পরিচালনা করার সুযোগ দেয় যাতে আপনি কেবলমাত্র কার্যকরভাবে সমস্ত কিছু আটকাচ্ছেন না।

উদাহরণস্বরূপ আপনি একটি মূলত একক থ্রেডেড সার্ভার লিখতে পারেন যা তবুও অনেকগুলি সমবর্তী সংযোগগুলি পরিচালনা করে। যতক্ষণ না সারিতে কোনও পৃথক ব্লক বেশি সময় নেয় না সার্ভারটি নতুন অনুরোধগুলিতে সাড়া দেয়।

যদি আপনার প্রোগ্রামটি ইভেন্টের প্রতিক্রিয়াটির পুরো জীবন ব্যয় করা ব্যতীত কিছুই না করে তবে এটি বেশ স্বাভাবিক হতে পারে। আপনি কেবলমাত্র আপনার ইভেন্ট হ্যান্ডলারগুলি মূল সারিটিতে চালানোর জন্য সেটআপ করেছেন এবং তারপরে ডিসপ্যাচ_মেইন () কল করুন এবং আপনার থ্রেড সুরক্ষার জন্য মোটেও উদ্বিগ্ন হওয়ার দরকার নেই।


11

আশা করি আমি আপনার প্রশ্নটি সঠিকভাবে বুঝতে পেরেছি যে আপনি ডিসপ্যাচ_স্যানসিচ এবং ডিসপ্যাচ_সেন্সের মধ্যে পার্থক্য সম্পর্কে ভাবছেন?

dispatch_async

অবিচ্ছিন্নভাবে একটি কাতারে ব্লকটি প্রেরণ করবে। মানে এটি ব্লকে কাতারে পাঠিয়ে দেবে এবং আপনার পদ্ধতিতে বাকী কোডটি কার্যকর করার আগে চালিয়ে যাওয়ার আগে এটি ফিরে আসার অপেক্ষা রাখে না।

dispatch_sync

ব্লকটি একটি কাতারে সমকালীনভাবে প্রেরণ করবে। এটি ব্লকটির সম্পাদনা শেষ না হওয়া অবধি পদ্ধতিতে অবশিষ্ট কোডের আর কোনও প্রয়োগকে আটকাবে।

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

শুভকামনা


1
ধন্যবাদ, তবে আমি মূল কাতারে থাকায় মূল কাতারে কিছু প্রেরণের সুবিধা সম্পর্কে জিজ্ঞাসা করছি।
হাঁস

9

এটি যেখানে দরকারী সেই এক জায়গাটি ইউআই ক্রিয়াকলাপগুলির জন্য যেমন দীর্ঘ অপারেশনের আগে একজন স্পিনার স্থাপন করা:

- (void) handleDoSomethingButton{

    [mySpinner startAnimating];

    (do something lengthy)
    [mySpinner stopAnimating];
}

কাজ করবে না, কারণ আপনি আপনার দীর্ঘ জিনিস চলাকালীন মূল থ্রেডটি ব্লক করছেন এবং ইউআইকিটকে আসলে স্পিনার শুরু করতে দিচ্ছেন না।

- (void) handleDoSomethingButton{
     [mySpinner startAnimating];

     dispatch_async (dispatch_get_main_queue(), ^{
          (do something lengthy)
          [mySpinner stopAnimating];
    });
}

রান লুপের নিয়ন্ত্রণ ফিরে আসবে, যা ইউআই আপডেট করার সময়সূচী তৈরি করবে, স্পিনারকে শুরু করবে, তারপরে প্রেরণ সারিতে পরবর্তী জিনিসটি পাবেন, এটি আপনার আসল প্রক্রিয়াজাতকরণ। আপনার প্রসেসিং হয়ে গেলে, অ্যানিমেশন স্টপটি কল করা হয় এবং আপনি রান লুপে ফিরে যান, যেখানে ইউআই স্টপটি সহ আপডেট হয়।


@ জেরেসরেটস হ্যাঁ তবে এটি বর্তমান রানলুপটি সম্পূর্ণ করতে দেয়।
ড্যান রোজনস্টার্ক

3
হ্যাঁ, তবে এটি এখনও ভয়াবহ। এটি এখনও ইউআইকে অবরুদ্ধ করে। আমি এর ঠিক পরে অন্য বোতাম টিপতে পারি। অথবা চেষ্টা করুন এবং স্ক্রোল। "(দীর্ঘায়িত কিছু করুন)" মূল থ্রেডে ঘটবে না এবং বোতামটি "ফিনিস" ক্লিক করতে দেওয়ার জন্য প্রেরণ_চ্যুতি গ্রহণযোগ্য সমাধান নয়।
জেরেসারটপস


1

অ্যাসিঙ্ক অর্থ অ্যাসিক্রোনাস এবং আপনার বেশিরভাগ সময় এটি ব্যবহার করা উচিত। টাস্কটি শেষ না হওয়া পর্যন্ত আপনাকে কখনই মূল থ্রেডে সিঙ্ক কল করতে হবে না কারণ এটি আপনার ইউআই লক করে দেবে। আপনি সুইফটে এটি করার আরও ভাল উপায়:

runThisInMainThread { () -> Void in
    // Run your code like this:
    self.doStuff()
}

func runThisInMainThread(block: dispatch_block_t) {
    dispatch_async(dispatch_get_main_queue(), block)
}

এটি আমার রেপোতে একটি স্ট্যান্ডার্ড ফাংশন হিসাবে অন্তর্ভুক্ত রয়েছে, এটি পরীক্ষা করে দেখুন: https://github.com/goktugyil/EZSwiftExtensions

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