যখন আপনার কোডের সিঙ্ক সংস্করণ এবং সিঙ্ক উভয়ই থাকতে হবে তখন কীভাবে ডিআরওয়াই নীতি লঙ্ঘন করবেন না?


15

আমি এমন একটি প্রকল্পে কাজ করছি যা একই যুক্তি / পদ্ধতির সিঙ্ক সংস্করণ এবং সিঙ্ক উভয়ই সমর্থন করে। সুতরাং উদাহরণস্বরূপ আমার থাকা দরকার:

public class Foo
{
   public bool IsIt()
   {
      using (var conn = new SqlConnection(DB.ConnString))
      {
         return conn.Query<bool>("SELECT IsIt FROM SomeTable");
      }
   }

   public async Task<bool> IsItAsync()
   {
      using (var conn = new SqlConnection(DB.ConnString))
      {
         return await conn.QueryAsync<bool>("SELECT IsIt FROM SomeTable");
      }
   }
}

এই পদ্ধতির জন্য অ্যাসিঙ্ক এবং সিঙ্ক লজিকটি প্রতিটি ক্ষেত্রে একরকম, বাদে যেটি একটি অ্যাসিঙ্ক এবং অন্যটি নয় except এই জাতীয় দৃশ্যে DRY নীতি লঙ্ঘন এড়াতে কি কোনও বৈধ উপায় আছে? আমি দেখেছি যে লোকেরা বলেছে যে আপনি একটি অ্যাসিঙ্ক পদ্ধতিতে গেটআউটটার () ব্যবহার করতে পারেন Get এই থ্রেড কি সব পরিস্থিতিতে নিরাপদ? এটি করার আরও ভাল উপায় আছে বা আমি যুক্তিটি নকল করতে বাধ্য?


1
আপনি এখানে কি করছেন সে সম্পর্কে আপনি আরও কিছু বলতে পারেন? বিশেষত, আপনি কীভাবে আপনার অ্যাসিনক্রোনাস পদ্ধতিতে অ্যাসিক্রোনারি অর্জন করছেন? হাই-লেটেনসি কাজের সিপিইউ আবদ্ধ বা আইও আবদ্ধ?
এরিক লিপার্ট

"একটি অ্যাসিঙ্ক এবং অন্যটি নয়" প্রকৃত পদ্ধতির কোড বা কেবল ইন্টারফেসের মধ্যে পার্থক্য কি? (পরিষ্কারভাবে কেবল ইন্টারফেসের জন্য আপনি পারেন return Task.FromResult(IsIt());)
আলেক্সি লেভেনকভ

এছাড়াও, সম্ভবত সিঙ্ক্রোনাস এবং অ্যাসিনক্রোনাস সংস্করণ উভয়ই উচ্চ-বিলম্বিত। কোন পরিস্থিতিতে কলকারী সিঙ্ক্রোনাস সংস্করণ ব্যবহার করবে এবং সেই কলার কীভাবে এই কল্পনাটি প্রশমিত করবে যে কলি বিলিয়ন বিলিয়ন ন্যানোসেকেন্ড নিতে পারে? সিঙ্ক্রোনাস সংস্করণটির ফোনকারীরা কি ইউআই কে ঝুলিয়ে দিচ্ছে তা কি যত্ন নেই? কোন ইউআই আছে? দৃশ্য সম্পর্কে আরও বলুন।
এরিক লিপার্ট

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

পছন্দ করুন
মার্কো

উত্তর:


15

আপনি আপনার প্রশ্নে বেশ কয়েকটি প্রশ্ন জিজ্ঞাসা করেছেন। আপনার চেয়ে আমি কিছুটা আলাদা করে ফেলব। তবে প্রথমে আমাকে সরাসরি প্রশ্নের উত্তর দিন।

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

আমাকে কেন ভেঙে দিন। আমরা এই প্রশ্নটি দিয়ে শুরু করব:


আমি দেখেছি যে লোকেরা বলে যে আপনি GetAwaiter().GetResult()একটি অ্যাসিঙ্ক পদ্ধতিতে ব্যবহার করতে পারেন এবং এটি আপনার সিঙ্ক পদ্ধতি থেকে প্রার্থনা করতে পারেন ? এই থ্রেড কি সব পরিস্থিতিতে নিরাপদ?

এই প্রশ্নের মূল বক্তব্যটি হ'ল "আমি কি সিঙ্ক্রোনাস পাথকে সহজলভ্য করে অ্যাসিক্রোনাস সংস্করণে একটি সুসংগত অপেক্ষা করতে পারি?"

আমাকে এই বিষয়টিতে সুস্পষ্টভাবে পরিষ্কার করা যাক এটি গুরুত্বপূর্ণ:

আপনি অবিলম্বে এই লোকদের কাছ থেকে যে কোনও পরামর্শ নেওয়া বন্ধ করে দিতে হবে

এটি চরম খারাপ পরামর্শ। অ্যাসিঙ্ক্রোনাস টাস্ক থেকে সিঙ্ক্রোনসিলে ফল আনা খুব বিপজ্জনক তবে যদি আপনার কাছে প্রমাণ না থাকে যে কাজটি স্বাভাবিকভাবে বা অস্বাভাবিকভাবে সম্পন্ন হয়েছে

এটি অত্যন্ত খারাপ পরামর্শের কারণটি হ'ল ভাল, এই দৃশ্যটি বিবেচনা করুন। আপনি লন কাঁচা কাটাতে চান তবে আপনার লন মাওয়ার ফলকটি নষ্ট হয়ে গেছে। আপনি এই কর্মপ্রবাহটি অনুসরণ করার সিদ্ধান্ত নিন:

  • কোনও ওয়েবসাইট থেকে একটি নতুন ব্লেড অর্ডার করুন। এটি একটি উচ্চ-ল্যাটেন্সি, অ্যাসিনক্রোনাস অপারেশন।
  • একযোগে অপেক্ষা করুন - অর্থাৎ আপনার ফলকটি হাতে না আসা পর্যন্ত ঘুমান
  • ব্লেড এসেছে কিনা তা পর্যায়ক্রমে মেলবক্সটি পরীক্ষা করে দেখুন।
  • বক্স থেকে ফলকটি সরান। এখন আপনি এটি হাতে আছে।
  • মওয়ারে ফলকটি ইনস্টল করুন।
  • ঘাস কাটা.

কি ঘটেছে? আপনি চিরদিনের জন্য ঘুমান কারণ মেলটি যাচাইয়ের ক্রিয়াকলাপটি এখন মেল আসার পরে ঘটে এমন কোনও কিছুতে প্রেরিত

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

আপনি যদি একটি অ্যাসিনক্রোনাস অপেক্ষা করেন তবে সবকিছু ঠিক আছে! আপনি পর্যায়ক্রমে মেলটি পরীক্ষা করে দেখুন এবং আপনি অপেক্ষা করার সময় আপনি একটি স্যান্ডউইচ তৈরি করেন বা আপনার করগুলি বা যা কিছু করেন; আপনি অপেক্ষা করার সময় আপনি কাজ করা চালিয়ে যান।

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

এই বিষয়ে আরও পড়ার জন্য, দেখুন

https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

স্টিফেন আমার চেয়ে বাস্তবের বিশ্বের পরিস্থিতি আরও ভালভাবে ব্যাখ্যা করেছেন।


এখন "অন্যান্য দিক" বিবেচনা করা যাক। আমরা কি অ্যাসিঙ্ক্রোনাস সংস্করণ তৈরি করে কোডটি ভাগ করে নিতে পারি কেবল কোনও কর্মী থ্রেডে সিঙ্ক্রোনাস সংস্করণটি?

যে সম্ভবত এবং প্রকৃতপক্ষে সম্ভবত নিম্নলিখিত কারণের জন্য একটি খারাপ ধারণা।

  • সিঙ্ক্রোনাস অপারেশন হাই-লেটেন্সি আইও কাজ করে থাকলে এটি অদক্ষ। এটি মূলত একজন শ্রমিককে নিয়োগ দেয় এবং কোনও কাজ শেষ না হওয়া পর্যন্ত সেই কর্মীকে ঘুমিয়ে দেয় । থ্রেডগুলি অত্যন্ত ব্যয়বহুল । তারা ডিফল্টরূপে সর্বনিম্ন এক মিলিয়ন বাইট অ্যাড্রেস স্পেস গ্রাস করে, তারা সময় নেয়, তারা অপারেটিং সিস্টেমের সংস্থান গ্রহণ করে; অকেজো কাজ করে আপনি কোনও সুতোর পোড়াতে চান না।

  • সুসংগত ক্রিয়াকলাপটি থ্রেড নিরাপদ হতে পারে না।

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

আরও পড়া; আবার, স্টিফেন খুব স্পষ্টভাবে এটি ব্যাখ্যা করেছেন:

টাস্ক.রুন ব্যবহার করবেন না কেন:

https://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-using.html

টাস্কের জন্য আরও "করুন এবং করবেন না" পরিস্থিতি un

https://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-dont-use.html


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


আপনি কী ব্যাখ্যা করতে পারেন যে কেন Task.Run(() => SynchronousMethod())অ্যাসিঙ্ক সংস্করণে ফিরে আসা ওপি চায় না?
গিলাইম সাসডি

2
@ গুইলুমাস্যাসিডি: মূল পোস্টারটি কাজটি কী তা এই প্রশ্নের জবাব দিয়েছে: এটি আইও বাধ্য bound কর্মী থ্রেডে আইও বাউন্ড টাস্কগুলি চালানো ব্যর্থ!
এরিক লিপার্ট

ঠিক আমি বুঝতে. আমি মনে করি আপনি ঠিকই আছেন, এবং @ স্ট্রিপলিং ওয়ারিয়র উত্তরও এটি আরও ব্যাখ্যা করে।
গিলাইম সাসডি

2
@ মারকো থ্রেডকে ব্লক করে এমন প্রায় কোনও কাজই শেষ পর্যন্ত (উচ্চ বোঝার নিচে) সমস্ত থ্রেডপুলের থ্রেড গ্রহণ করবে (যা সাধারণত অ্যাসিঙ্ক অপারেশনগুলি সম্পন্ন করতে ব্যবহৃত হত)। ফলস্বরূপ সমস্ত থ্রেড অপেক্ষায় থাকবে এবং কোডের "অ্যাসিঙ্ক অপারেশন সমাপ্ত" অপারেশনগুলি চালনা করার জন্য কোনওটিই উপলভ্য হবে না। বেশিরভাগ ওয়ার্কআরউন্ডগুলি লোড লোডের দৃশ্যে ভাল থাকে (প্রতিটি একক ক্রিয়াকলাপের অংশ হিসাবে প্রচুর থ্রেড এমনকি ২-৩ টি অবরুদ্ধ রয়েছে) ... এবং যদি আপনি গ্যারান্টি দিতে পারেন যে অ্যাসিঙ্ক অপারেশনটি সম্পূর্ণ করে নতুন ওএস থ্রেডে চলেছে (থ্রেড পুল নয়) এটি এমনকি সমস্ত মামলার জন্যও কাজ করতে পারে (আপনি বেশি দাম দিতে পারেন)
আলেক্সি লেভেনকভ

2
কখনও কখনও "কেবল কোনও শ্রমিকের থ্রেডে সিঙ্ক্রোনাস সংস্করণ করুন" ব্যতীত অন্য কোনও উপায় নেই। উদাহরণস্বরূপ, Dns.GetHostEntryAsync.NET এবং FileStream.ReadAsyncনির্দিষ্ট ধরণের ফাইলের ক্ষেত্রে এটি প্রয়োগ করা হয় । ওএস কেবল কোনও অ্যাসিঙ্ক ইন্টারফেস সরবরাহ করে না, সুতরাং রানটাইমটিকে এটি নকল করতে হবে (এবং এটি ভাষা নির্দিষ্ট নয় - বলুন, এরলং রানটাইম কর্মী প্রক্রিয়াগুলির পুরো ট্রি চালায় , প্রতিটি ভিতরে একাধিক থ্রেড সহ, ব্লক-অন-ব্লকিং ডিস্ক I / O এবং নাম সরবরাহ করে রেজোলিউশন)।
জোকার_ভিডি

6

এইটির একটিতে একটি আকার-ফিট-সব উত্তর দেওয়া কঠিন। দুর্ভাগ্যক্রমে অ্যাসিক্রোনাস এবং সিঙ্ক্রোনাস কোডের মধ্যে পুনরায় ব্যবহারের সহজ এবং নিখুঁত উপায় নেই। তবে এখানে কয়েকটি নীতির কথা বিবেচনা করুন:

  1. অ্যাসিঙ্ক্রোনাস এবং সিঙ্ক্রোনাস কোড প্রায়শই মৌলিকভাবে আলাদা। অ্যাসিঙ্ক্রোনাস কোডে সাধারণত একটি বাতিলকরণ টোকেন অন্তর্ভুক্ত করা উচিত, উদাহরণস্বরূপ। এবং প্রায়শই এটি বিভিন্ন পদ্ধতিতে কল করা (যেমন আপনার উদাহরণটি অন্যটিতে কল Query()করে QueryAsync()) বা বিভিন্ন সেটিংসের সাথে সংযোগ স্থাপন করে। এমনকি এটি কাঠামোগতভাবে সমান হলেও, প্রায়শই আচরণে যথেষ্ট পার্থক্য থাকে তাদের বিভিন্ন প্রয়োজনীয়তার সাথে পৃথক কোড হিসাবে বিবেচনা করা হয়। ফাইল ক্লাসে পদ্ধতিসমূহের অ্যাসিঙ্ক এবং সিঙ্ক বাস্তবায়নের মধ্যে পার্থক্যগুলি নোট করুন , উদাহরণস্বরূপ: তাদের একই কোডটি ব্যবহার করার চেষ্টা করা হয় না
  2. যদি আপনি কোনও ইন্টারফেস বাস্তবায়নের স্বার্থে একটি অ্যাসিনক্রোনাস পদ্ধতির স্বাক্ষর সরবরাহ করে থাকেন তবে আপনার একটি সিঙ্ক্রোনাস বাস্তবায়ন ঘটে (যেমন আপনার পদ্ধতিটি কী করে সে সম্পর্কে অন্তর্নিহিত কিছু নেই) আপনি কেবল ফিরে আসতে পারেন Task.FromResult(...)
  3. যা যুক্তির কোন সমলয় টুকরা হয় দুটি পদ্ধতির মধ্যে একই পৃথক সাহায্যকারী পদ্ধতি নিষ্কাশিত এবং উভয় পদ্ধতিতে leveraged করা যেতে পারে।

শুভকামনা।


-2

সহজ; সিঙ্ক্রোনাসকে এসিঙ্কটি কল করুন। এমনকি এটি Task<T>করার জন্য একটি সহজ পদ্ধতি রয়েছে :

public class Foo
{
   public bool IsIt()
   {
      var task = IsItAsync(); //no await here; we want the Task

      //Some tasks end up scheduled to run before you get them;
      //don't try to run them a second time
      if((int)task.Status > (int)TaskStatus.Created)
          //this call will block the current thread,
          //and unlike Run()/Wait() will prefer the current 
          //thread's TaskScheduler instead of a new thread.
          task.RunSynchronously(); 

      //if IsItAsync() can throw exceptions,
      //you still need a Wait() call to bring those back from the Task
      try{ 
          task.Wait();
          return task.Result;
      }
      catch(Exception ex) 
      { 
          //Handle IsItAsync() exceptions here;
          //remember to return something if you don't rethrow              
      }
   }

   public async Task<bool> IsItAsync()
   {
      // Some async logic
   }
}

1
আমার উত্তরটি দেখুন কেন এটি সবচেয়ে খারাপ অভ্যাস যা আপনাকে কখনই করা উচিত নয়।
এরিক লিপার্ট

1
আপনার উত্তরটি গেটএওয়েটার () এর সাথে সম্পর্কিত Get আমি তা এড়িয়ে গেছি। বাস্তবতাটি হ'ল কখনও কখনও আপনাকে কোনও পদ্ধতি স্ট্রিংয়ে সিঙ্ক্রোনালি চালাতে হয় যাতে এ্যাসিঙ্ক তৈরি করা যায় না call সিঙ্কের অপেক্ষা যদি কখনও না করা হয়, তবে সি # দলের একজন সদস্য (প্রাক্তন) সদস্য হিসাবে, দয়া করে আমাকে বলুন যে আপনি কেন ত্রিপিএলে একটি অ্যাসিনক্রোনাস টাস্কের জন্য সুসংগতভাবে অপেক্ষা করার দুটি নয়, দুটি উপায় রাখেন।
কিথস

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