সত্তা ফ্রেমওয়ার্ক অনুসন্ধানযোগ্য async


99

সত্তা ফ্রেমওয়ার্ক 6 ব্যবহার করে আমি কয়েকটি ওয়েব এপিআই স্টাফ নিয়ে কাজ করছি এবং আমার নিয়ামক পদ্ধতির একটি হল "সমস্ত পান" যা আমার ডাটাবেস থেকে কোনও টেবিলের বিষয়বস্তু হিসাবে প্রত্যাশা করে IQueryable<Entity>। আমার সংগ্রহশালায় আমি ভাবছি যে এই অ্যাসিঙ্ক্রোনসিটি করার জন্য কোনও সুবিধাজনক কারণ আছে কেননা আমি এসিঙ্কের সাথে ইএফ ব্যবহারে নতুন new

মূলত এটিতে সিদ্ধ হয়

 public async Task<IQueryable<URL>> GetAllUrlsAsync()
 {
    var urls = await context.Urls.ToListAsync();
    return urls.AsQueryable();
 }

বনাম

 public IQueryable<URL> GetAllUrls()
 {
    return context.Urls.AsQueryable();
 }

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


4
প্রসঙ্গ.আরলস হ'ল DbSet <URL> প্রকারের যা আইকোয়্যারেবল << URL> প্রয়োগ করে তাই। এমএসডিএন.মাইক্রোসফট.ইন- ইউস / লিবারি/gg696460(v=vs.113).aspx ধরে নিলে আপনি EF যে ধাঁচগুলি সরবরাহ করেছেন তা অনুসরণ করেছেন, বা আপনার জন্য প্রসঙ্গ তৈরি করে এমন সরঞ্জাম ব্যবহার করেছেন।
শন বি

উত্তর:


229

সমস্যাটি দেখে মনে হচ্ছে আপনি সত্তা ফ্রেমওয়ার্কের সাথে কীভাবে async / কাজের প্রতীক্ষা করছেন তা ভুল বুঝেছেন।

সত্তা ফ্রেমওয়ার্ক সম্পর্কে

সুতরাং, আসুন এই কোডটি দেখুন:

public IQueryable<URL> GetAllUrls()
{
    return context.Urls.AsQueryable();
}

এবং এর ব্যবহারের উদাহরণ:

repo.GetAllUrls().Where(u => <condition>).Take(10).ToList()

সেখানে কি হয়?

  1. আমরা IQueryableব্যবহার করে অবজেক্ট (এখনও ডাটাবেস অ্যাক্সেস না) পাচ্ছিrepo.GetAllUrls()
  2. আমরা একটি নতুন তৈরি IQueryableনির্দিষ্ট শর্ত ব্যবহার করে অবজেক্ট.Where(u => <condition>
  3. আমরা IQueryableনির্দিষ্ট পেজিং সীমা ব্যবহার করে একটি নতুন অবজেক্ট তৈরি করি.Take(10)
  4. আমরা ডাটাবেস ব্যবহার করে ফলাফল পুনরুদ্ধার .ToList()। আমাদের IQueryableঅবজেক্টটি স্কয়ারে (যেমন select top 10 * from Urls where <condition>) সংকলিত হয় । এবং ডাটাবেস সূচীগুলি ব্যবহার করতে পারে, এসকিউএল সার্ভার আপনাকে আপনার ডাটাবেস থেকে কেবলমাত্র 10 টি বস্তু প্রেরণ করবে (ডাটাবেসে থাকা সমস্ত বিলিয়ন ইউআরএল নয়)

ঠিক আছে, আসুন প্রথম কোডটি দেখুন:

public async Task<IQueryable<URL>> GetAllUrlsAsync()
{
    var urls = await context.Urls.ToListAsync();
    return urls.AsQueryable();
}

ব্যবহারের একই উদাহরণ সহ আমরা পেয়েছি:

  1. আমরা আপনার ডাটাবেসে সঞ্চিত সমস্ত বিলিয়ন ইউআরএল মেমরিতে লোড করছি await context.Urls.ToListAsync();
  2. আমরা স্মৃতি ওভারফ্লো পেয়েছি। আপনার সার্ভারকে মেরে ফেলার সঠিক উপায়

সম্পর্কে async / প্রতীক্ষা

কেন async / অপেক্ষার ব্যবহার পছন্দ? আসুন এই কোডটি দেখুন:

var stuff1 = repo.GetStuff1ForUser(userId);
var stuff2 = repo.GetStuff2ForUser(userId);
return View(new Model(stuff1, stuff2));

এখানে কি হয়?

  1. লাইন 1 এ শুরু var stuff1 = ...
  2. আমরা স্কয়ার সার্ভারে অনুরোধটি প্রেরণ করি যা আমরা কিছু স্টাফ 1 পেতে চাই userId
  3. আমরা অপেক্ষা করি (বর্তমান থ্রেড অবরুদ্ধ)
  4. আমরা অপেক্ষা করি (বর্তমান থ্রেড অবরুদ্ধ)
  5. .....
  6. SQL সার্ভার আমাদের প্রতিক্রিয়া প্রেরণ
  7. আমরা লাইন 2 এ চলেছি var stuff2 = ...
  8. আমরা স্কিএল সার্ভারে অনুরোধটি প্রেরণ করি যা আমরা কিছু স্টাফ 2 পেতে চাই userId
  9. আমরা অপেক্ষা করি (বর্তমান থ্রেড অবরুদ্ধ)
  10. এবং আবার
  11. .....
  12. SQL সার্ভার আমাদের প্রতিক্রিয়া প্রেরণ
  13. আমরা ভিউ রেন্ডার করি

সুতরাং আসুন এটির একটি অ্যাসিঙ্ক সংস্করণটি দেখুন:

var stuff1Task = repo.GetStuff1ForUserAsync(userId);
var stuff2Task = repo.GetStuff2ForUserAsync(userId);
await Task.WhenAll(stuff1Task, stuff2Task);
return View(new Model(stuff1Task.Result, stuff2Task.Result));

এখানে কি হয়?

  1. স্টাফ 1 (লাইন 1) পাওয়ার জন্য আমরা এসকিএল সার্ভারে অনুরোধ পাঠাব
  2. স্টাফ 2 (লাইন 2) পাওয়ার জন্য আমরা এসকিএল সার্ভারে অনুরোধটি প্রেরণ করি
  3. আমরা স্কিএল সার্ভারের প্রতিক্রিয়াগুলির জন্য অপেক্ষা করি, তবে বর্তমান থ্রেডটি অবরুদ্ধ নয়, তিনি অন্য ব্যবহারকারীদের কাছ থেকে প্রশ্নগুলি পরিচালনা করতে পারেন
  4. আমরা ভিউ রেন্ডার করি

এটি করার সঠিক উপায়

এখানে খুব ভাল কোড:

using System.Data.Entity;

public IQueryable<URL> GetAllUrls()
{
   return context.Urls.AsQueryable();
}

public async Task<List<URL>> GetAllUrlsByUser(int userId) {
   return await GetAllUrls().Where(u => u.User.Id == userId).ToListAsync();
}

দ্রষ্টব্য, আইকিউয়েরেবলের জন্য using System.Data.Entityপদ্ধতিটি ব্যবহার করার জন্য আপনাকে অবশ্যই যুক্ত করতে হবে ToListAsync()

দ্রষ্টব্য, আপনার যদি ফিল্টারিং এবং পেজিং এবং স্টাফের প্রয়োজন না হয় তবে আপনার সাথে কাজ করার দরকার নেই IQueryable। আপনি কেবল ব্যবহার await context.Urls.ToListAsync()এবং উপাদানযুক্ত সঙ্গে কাজ করতে পারেন List<Url>


4
@ কোরিজন আইআইএস আর্কিটেকচারের পরিচিতি থেকে i2.iis.net/media/7188126/… ছবি দেখছেন আমি বলতে পারি যে আইআইএস-এর সমস্ত অনুরোধগুলি অ্যাসিক্রোনাস পদ্ধতিতে প্রক্রিয়াজাত করা হয়েছে
ভিক্টর লোভা

7
যেহেতু আপনি GetAllUrlsByUserপদ্ধতিতে ফলাফল সেটটিতে অভিনয় করছেন না , তাই আপনাকে এ্যাসিঙ্ক করার দরকার নেই। কেবল টাস্কটি ফিরিয়ে দিন এবং সংযোজক দ্বারা উত্পাদিত হওয়া থেকে আপনার নিজের একটি অপ্রয়োজনীয় রাষ্ট্র মেশিন সংরক্ষণ করুন
জনাথন সুলিঞ্জার

4
@ জোনাথনসুলিঞ্জার যদিও এটি সুখের প্রবাহে কাজ করবে, তবে এর কোনও পার্শ্ব-প্রতিক্রিয়া নেই যে কোনও ব্যতিক্রম এখানে উপস্থিত হবে না এবং অপেক্ষারত প্রথম স্থানে প্রচার করবে? (এটি খুব খারাপ নয়, তবে এটি আচরণের পরিবর্তন?)
হেনরি

9
আকর্ষণীয় কারও নজরে নেই যে "এসআইএনকি / অপেক্ষার বিষয়ে" তে দ্বিতীয় কোড উদাহরণটি সম্পূর্ণ অজ্ঞানসই, কারণ এটি একটি ব্যতিক্রম ঘটায় যেহেতু ইএফ এবং ইএফ কোর উভয়ই থ্রেড নিরাপদ নয়, সুতরাং সমান্তরালে চালানোর চেষ্টা কেবল একটি ব্যতিক্রম ছুঁড়ে ফেলবে
Tseng

4
যদিও এই উত্তরটি সঠিক, তবুও আমি ব্যবহারটি এড়াতে asyncএবং awaitআপনি যদি তালিকাটি দিয়ে কিছু না করেন তবে সুপারিশ করব । কলার awaitএটি করতে দিন। আপনি যখন এই পর্যায়ে কলটির অপেক্ষায় রয়েছেন return await GetAllUrls().Where(u => u.User.Id == userId).ToListAsync();তখন আপনি অ্যাসেম্বলিটি ডিসম্পাইল করে আইএলটি দেখলে আপনি একটি অতিরিক্ত অ্যাসিঙ্ক র‌্যাপার তৈরি করেন।
আলী খাকপুরি

10

আপনি যে উদাহরণটি পোস্ট করেছেন তার মধ্যে একটি বিস্তর পার্থক্য রয়েছে, প্রথম সংস্করণ:

var urls = await context.Urls.ToListAsync();

এটি খারাপ , এটি মূলত করে select * from table, সমস্ত ফলাফলকে মেমরিতে ফিরিয়ে দেয় এবং তারপরে ডাটাবেসের বিরুদ্ধে না করে whereমেমরি সংগ্রহের ক্ষেত্রে এর বিপরীতে প্রয়োগ select * from table where...করে।

দ্বিতীয় পদ্ধতিটি আসলে ডাটাবেসে হিট করবে না যতক্ষণ না কোনও ক্যোয়ারী প্রয়োগ করা হয় IQueryable(সম্ভবত একটি লিনাক .Where().Select()শৈলীর ক্রিয়াকলাপের মাধ্যমে যা কেবলমাত্র ডিবি মানগুলি দিয়ে আসে যা কোয়েরির সাথে মেলে।

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

তবে প্রধান পার্থক্য (এবং সুবিধা) হ'ল asyncসংস্করণটি আরও সমবর্তী অনুরোধগুলিকে মঞ্জুরি দেয় কারণ এটি প্রক্রিয়াকরণ থ্রেডকে ব্লক করে না যদিও এটি আইও সম্পূর্ণ হওয়ার অপেক্ষায় থাকে (ডিবি ক্যোয়ারী, ফাইল অ্যাক্সেস, ওয়েব অনুরোধ ইত্যাদি)।


7
আইকিউয়েরেবলের জন্য কোনও কোয়েরি প্রয়োগ না করা অবধি .... আইকুয়্যারেবল.কেনই না এবং আইকোয়্যারেবল। নির্বাচন করুন কোয়েরিটি কার্যকর করতে বাধ্য করুন। পূর্ববর্তীটি একটি ভবিষ্যদ্বাণী প্রয়োগ করে এবং পরবর্তীটি একটি প্রক্ষেপণ প্রয়োগ করে। টোললিস্ট, টোআররে, সিঙ্গল বা ফার্স্টের মতো ম্যাটামাইজিং অপারেটর ব্যবহার না করা অবধি এটি কার্যকর করা হয় না।
জেজেএস

0

লং স্টোরি সংক্ষিপ্ত,
IQueryableরুন প্রক্রিয়া স্থগিত করার জন্য এবং প্রথমে অন্যান্য IQueryableএক্সপ্রেশনগুলির সাথে মিল রেখে অভিব্যক্তিটি তৈরির জন্য ডিজাইন করা হয়েছে , এবং তারপরে পুরো ব্যাখ্যাটি ব্যাখ্যা করে এবং চালায়।
তবে ToList()মেথড (বা এর মতো কয়েকটি ধরণের পদ্ধতি) হ'ল তাত্ক্ষণিকভাবে "যেমন হয়" তে চালানো।
আপনার প্রথম পদ্ধতি ( GetAllUrlsAsync), উদ্দেশ্যমূলকভাবে চলবে, কারণ এটি পদ্ধতি IQueryableঅনুসরণ করে ToListAsync()। অতএব এটি তাত্ক্ষণিকভাবে চালিত হয় (অ্যাসিনক্রোনাস), এবং একগুচ্ছ IEnumerableএস প্রদান করে।
ইতোমধ্যে আপনার দ্বিতীয় পদ্ধতি ( GetAllUrls) চালাবে না। পরিবর্তে, এটি একটি অভিব্যক্তি প্রদান করে এবং এই পদ্ধতির কলার অভিব্যক্তিটি চালনার জন্য দায়বদ্ধ।

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