.NET - অভিধান লকিং বনাম সাম্প্রতিক অভিধান


131

ConcurrentDictionaryপ্রকারভেদে আমি পর্যাপ্ত তথ্য পাই না , তাই আমি ভেবেছিলাম যে আমি এটি সম্পর্কে এখানে জিজ্ঞাসা করব।

বর্তমানে, আমি Dictionaryএকাধিক থ্রেড দ্বারা নিয়মিত অ্যাক্সেস করা সমস্ত ব্যবহারকারীকে ধরে রাখতে একটি ব্যবহার করি (থ্রেড পুল থেকে, সুতরাং থ্রেডের সঠিক পরিমাণ নেই), এবং এটি অ্যাক্সেসকে সিঙ্ক্রোনাইজ করেছে।

আমি সম্প্রতি জানতে পেরেছিলাম যে .NET 4.0 এ থ্রেড-নিরাপদ সংগ্রহের একটি সেট ছিল এবং এটি খুব আনন্দদায়ক বলে মনে হচ্ছে। আমি ভাবছিলাম, 'আরও কার্যকর এবং পরিচালনা করতে সহজতর' বিকল্পটি কী হবে, কারণ আমার কাছে Dictionaryসিঙ্ক্রোনাইজড অ্যাক্সেস সহ একটি স্বাভাবিক থাকার মধ্যে বা ConcurrentDictionaryইতিমধ্যে থ্রেড-নিরাপদ এমন একটি বিকল্প রয়েছে ।

.NET 4.0 এর উল্লেখ ConcurrentDictionary


উত্তর:


146

একটি থ্রেড-নিরাপদ সংগ্রহ বনাম একটি থ্রেডসেফ-সংগ্রহ অন্যরকমভাবে দেখা যায়।

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

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

এখন এই বিবেচনা করুন। একজন কেরানির সাথে দোকানে, আপনি যদি লাইনের সামনের দিকে যেতে পারেন এবং সেই ক্লারিকে "আপনার কি কোনও টয়লেট পেপার আছে" জিজ্ঞাসা করুন, এবং তিনি "হ্যাঁ" বলেছেন, এবং তারপরে আপনি "ঠিক আছে, আমি" যাই আমি যখন আপনার কতটা প্রয়োজন জানি তখন আপনার কাছে ফিরে আসব ", তারপরে আপনি যখন লাইনের সামনের দিকে ফিরে আসবেন, তখন অবশ্যই স্টোরটি বিক্রি হয়ে যাবে। থ্রেডসেফ সংগ্রহ দ্বারা এই দৃশ্যটি প্রতিরোধ করা হয়নি।

একটি থ্রেডস্যাফ সংগ্রহটি গ্যারান্টি দেয় যে এর অভ্যন্তরীণ ডেটা স্ট্রাকচারগুলি সর্বদা বৈধ, এমনকি একাধিক থ্রেড থেকে অ্যাক্সেস করা হলেও।

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

কোনও থ্রেডসেফ সংগ্রহটি গ্যারান্টি দেয় না যে থ্রেডের ক্রমিক ক্রিয়াকলাপগুলি সমস্ত তার অভ্যন্তরীণ ডেটা কাঠামোর একই "স্ন্যাপশট" এ কাজ করে, যার অর্থ এই যে আপনার যদি কোডটি থাকে তবে:

if (tree.Count > 0)
    Debug.WriteLine(tree.First().ToString());

আপনি একটি নালরফেরান এক্সেপশন পেতে পারেন কারণ অভ্যন্তর tree.Countএবং tree.First()অন্য একটি থ্রেড গাছের অবশিষ্ট নোডগুলি সাফ করেছে, যার অর্থ First()ফিরে আসবে null

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


9
আমি যখনই এই নিবন্ধটি পড়েছি তবুও এটি সত্য হলেও, আমরা কোনওভাবেই ভুল পথে নামছি।
স্কোপ_ক্রিপ

19
থ্রেড-সক্ষম সক্ষম অ্যাপ্লিকেশনটির প্রধান সমস্যা হ'ল মিউটেটেবল ডেটা স্ট্রাকচার। যদি আপনি তা এড়াতে পারেন তবে আপনি নিজেকে বিপদ থেকে উদ্ধার করবেন।
লাসে ভি কার্লসেন

89
এটি থ্রেড সুরক্ষার একটি দুর্দান্ত ব্যাখ্যা, তবে আমি সাহায্য করতে পারি না তবে মনে হয় এটি আসলে ওপি-র প্রশ্নের সমাধান করে না। ওপি কী জিজ্ঞাসা করেছিল (এবং আমি পরবর্তীকালে এই প্রশ্নটি সন্ধান করতে পেরেছি) তা হ'ল নেট 4+ এর মধ্যে নির্মিত প্রকারটি Dictionaryব্যবহার করে একটি মান ব্যবহার করা এবং নিজেকে লক করা পরিচালনা করার মধ্যে পার্থক্য ConcurrentDictionary। আমি আসলে কিছুটা বিস্মিত হয়েছি যে এটি গৃহীত হয়েছিল।
mclark1129

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

2
আমি মনে করি @ লাসেভি.কার্লসেন কী বলতে চেষ্টা করছেন, তা কি ... থ্রেড সুরক্ষা অর্জন করা সহজ, তবে আপনি কীভাবে সেই সুরক্ষাটি পরিচালনা করছেন তাতে আপনাকে অবশ্যই এক স্তরের একমত হতে হবে। নিজেকে এটিকে জিজ্ঞাসা করুন, "বস্তুর থ্রেড-সুরক্ষিত রেখে আমি কি একই সাথে আরও বেশি কাজ করতে পারি?" এই উদাহরণটি বিবেচনা করুন: দুটি গ্রাহক বিভিন্ন আইটেম ফিরে আসতে চান। আপনি যখন ম্যানেজার হিসাবে, আপনার স্টোরটি পুনরায় লক করতে যান, আপনি কি কেবলমাত্র একটি ট্রিপে উভয় আইটেমটি পুনরায় চালু করতে পারবেন না এবং এখনও উভয় গ্রাহকের অনুরোধ পরিচালনা করতে পারবেন, বা আপনি যখনই কোনও গ্রাহক কোনও জিনিস ফেরত যাবেন তখন আপনি কি ট্রিপ করতে যাচ্ছেন?
আলেকজান্দ্রু

68

থ্রেড-নিরাপদ সংগ্রহগুলি ব্যবহার করার সময় আপনার এখনও খুব সতর্কতা অবলম্বন করা উচিত কারণ থ্রেড-সেফের অর্থ এই নয় যে আপনি সমস্ত থ্রেডিংয়ের বিষয় উপেক্ষা করতে পারেন। যখন কোনও সংগ্রহ নিজেকে থ্রেড-সেফ হিসাবে বিজ্ঞাপন দেয়, সাধারণত এর অর্থ হ'ল একাধিক থ্রেড একসাথে পড়া এবং লেখার সময়ও এটি একটি সামঞ্জস্যপূর্ণ অবস্থায় থেকে যায়। তবে এর অর্থ এই নয় যে একক থ্রেড ফলাফলগুলির একটি "যৌক্তিক" ক্রম দেখবে যদি এটি একাধিক পদ্ধতিতে কল করে।

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

সুতরাং এগুলি ব্যবহার করুন, তবে ভাববেন না যে এটি আপনাকে সমস্ত সম্মতিযুক্ত সমস্যা উপেক্ষা করার জন্য একটি বিনামূল্যে পাস দেয়। আপনার এখনও সতর্ক হওয়া দরকার।


4
সুতরাং মূলত আপনি বলছেন আপনি যদি অবজেক্টটি সঠিকভাবে ব্যবহার না করেন তবে এটি কাজ করবে না?
কেওসপ্যান্ডিওন

3
মূলত আপনার প্রচলিত কনটেন্টস -> অ্যাডের পরিবর্তে ট্র্যাডএড ব্যবহার করতে হবে।
কেওসপ্যান্ডিয়ন

3
@ ব্রুনো: না you
মার্ক বাইয়ার্স

13
এখানে কার্ট শোনার অর্থ নয়, তবে TryGetValueসর্বদা এরই অংশ ছিল Dictionaryএবং এটি সর্বদা প্রস্তাবিত পদ্ধতির ছিল। গুরুত্বপূর্ণ "সমবর্তী" পদ্ধতিগুলি যা ConcurrentDictionaryপরিচয় করিয়ে দেয় তা হ'ল AddOrUpdateএবং GetOrAdd। সুতরাং, ভাল উত্তর, কিন্তু একটি ভাল উদাহরণ চয়ন করতে পারে।
অ্যারোনআউট

4
ডান - লেনদেনের মতো ডাটাবেসের বিপরীতে, বেশিরভাগ একযোগে ইন-মেমরি অনুসন্ধান কাঠামো বিচ্ছিন্ন হওয়ার ধারণা মিস করে , তারা কেবলমাত্র অভ্যন্তরীণ ডেটা কাঠামো সঠিক বলে গ্যারান্টি দেয়।
চ্যাং

39

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

আমি বলব, কেবল কনক্র্যান্টড অভিধান ব্যবহার করুন use


15

আমি মনে করি যে সমকালীন অভিধান .GETOrAdd পদ্ধতিটি হ'ল বেশিরভাগ মাল্টি-থ্রেডেড দৃশ্যের প্রয়োজন।


1
আমি ট্রাইজিটটিও ব্যবহার করব, অন্যথায় আপনি প্রতিবার কীটি ইতিমধ্যে উপস্থিত থাকার সময় দ্বিতীয় বার প্যারামিটারটি getOrAd এ শুরু করার চেষ্টাটি নষ্ট করবেন।
জোরিট স্কিপ্সার

7
গেটআরএডএডের ওভারলোড গেটআরএড (টি কে, ফানক <টিকি, টিভিয়াল>) রয়েছে , সুতরাং দ্বিতীয় প্যারামিটারটি অভিধানে অস্তিত্ব না থাকলে কেবল অলস-সূচনা হতে পারে। ট্রাইগেটভ্যালু ছাড়াও ডেটা আনার ক্ষেত্রে ব্যবহৃত হয়, পরিবর্তিত হয় না। এই পদ্ধতির প্রত্যেকটিতে পরবর্তী কলগুলির কারণ হতে পারে যে অন্য থ্রেড দুটি কলের মধ্যে কী যুক্ত বা সরিয়ে ফেলেছে।
sgnsajgon

লাসের পোস্টটি দুর্দান্ত হলেও এটি প্রশ্নের উত্তর হওয়া উচিত।
16'16 এ স্পাইভিনিয়াস

13

.Net 3.5sp1 এর জন্য আপনি কী প্রতিক্রিয়াশীল এক্সটেনশন দেখেছেন? জন স্কিটির মতে, তারা .Net3.5 এসপি 1 এর জন্য সমান্তরাল এক্সটেনশান এবং সমবর্তী ডেটা স্ট্রাকচারের একটি বান্ডিলকে ব্যাকপোর্ট করেছে।

নেট 4 বিটা 2 এর জন্য নমুনার একটি সেট রয়েছে, যা তাদের সমান্তরাল এক্সটেনশানগুলি কীভাবে ব্যবহার করতে হয় সে সম্পর্কে দুর্দান্তভাবে বিশদে বর্ণনা করে।

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

সম্পাদনা করুন : .NET 4 সমান্তরাল অভিধান এবং নিদর্শন।

মাইক্রোসফ্ট প্যাটার্নস অফ প্যারেলেল প্রোগ্রামিং নামে একটি পিডিএফ প্রকাশ করেছে। এটি ডাউনলোড করার উপযুক্ত মূল্য হিসাবে এটি সত্যই সুন্দর বিবরণে বর্ণিত। নেট 4 সমান্তরাল এক্সটেনশানগুলি এবং এড়ানোর জন্য অ্যান্টি প্যাটার্নগুলির জন্য সঠিক প্যাটার্নগুলি ব্যবহার করা উচিত। এটা এখানে.


4

মূলত আপনি নতুন সমকালীন অভিধানের সাথে যেতে চান। বাক্সের ঠিক বাইরে থ্রেড নিরাপদ প্রোগ্রামগুলি তৈরি করতে আপনাকে কম কোড লিখতে হবে।


আমি সামনের ডিকশনারি নিয়ে এগিয়ে গেলে কি কোনও সমস্যা আছে?
kbvishnu

1

ConcurrentDictionaryযদি এটা পরিপূর্ণ একটি মহান বিকল্প সব আপনার থ্রেড-নিরাপত্তা চাহিদা। যদি এটি না হয় তবে আপনার অন্য কথায় কিছুটা জটিল কিছু করছেন, একটি সাধারণ Dictionary+ lockআরও ভাল বিকল্প হতে পারে। উদাহরণস্বরূপ বলতে দিন যে আপনি অভিধানে কিছু অর্ডার যুক্ত করছেন এবং আপনি অর্ডারগুলির মোট পরিমাণ আপডেট রাখতে চান। আপনি এই জাতীয় কোড লিখতে পারেন:

private ConcurrentDictionary<int, Order> _dict;
private Decimal _totalAmount = 0;

while (await enumerator.MoveNextAsync())
{
    Order order = enumerator.Current;
    _dict.TryAdd(order.Id, order);
    _totalAmount += order.Amount;
}

এই কোডটি থ্রেড নিরাপদ নয়। _totalAmountক্ষেত্রটি আপডেট করে একাধিক থ্রেড এটি দূষিত অবস্থায় ফেলে থাকতে পারে। সুতরাং আপনি এটির সাহায্যে এটি রক্ষা করার চেষ্টা করতে পারেন lock:

_dict.TryAdd(order.Id, order);
lock (_locker) _totalAmount += order.Amount;

এই কোডটি "নিরাপদ" তবে থ্রেডটি নিরাপদে নেই। _totalAmountঅভিধানে এন্ট্রিগুলির সাথে সামঞ্জস্য রয়েছে এমন কোনও গ্যারান্টি নেই । অন্য থ্রেড একটি ইউআই উপাদান আপডেট করার জন্য, এই মানগুলি পড়ার চেষ্টা করতে পারে:

Decimal totalAmount;
lock (_locker) totalAmount = _totalAmount;
UpdateUI(_dict.Count, totalAmount);

দ্য totalAmountঅভিধানে অর্ডারের গণনা মিলা নাও করতে পারে। প্রদর্শিত পরিসংখ্যান ভুল হতে পারে। এই মুহুর্তে আপনি বুঝতে পারবেন যে lockঅভিধানটি আপডেট করার অন্তর্ভুক্ত করার জন্য আপনার অবশ্যই সুরক্ষা প্রসারিত করতে হবে :

// Thread A
lock (_locker)
{
    _dict.TryAdd(order.Id, order);
    _totalAmount += order.Amount;
}

// Thread B
int ordersCount;
Decimal totalAmount;
lock (_locker)
{
    ordersCount = _dict.Count;
    totalAmount = _totalAmount;
}
UpdateUI(ordersCount, totalAmount);

এই কোডটি পুরোপুরি নিরাপদ তবে একটি ব্যবহারের সমস্ত সুবিধা ConcurrentDictionaryচলে গেছে।

  1. পারফরম্যান্সটি সাধারণ ব্যবহারের চেয়ে খারাপ হয়ে গেছে Dictionaryকারণ অভ্যন্তরের অভ্যন্তরীণ লকিং ConcurrentDictionaryএখন অপব্যয় এবং অপ্রয়োজনীয়।
  2. ভাগ করা ভেরিয়েবলগুলির সুরক্ষিত ব্যবহারের জন্য আপনাকে অবশ্যই আপনার সমস্ত কোড পর্যালোচনা করতে হবে।
  3. আপনি একটি বিশ্রী এপিআই ব্যবহার করে আটকে আছেন ( TryAdd?,AddOrUpdate ?) ।

সুতরাং আমার পরামর্শটি হ'ল: একটি Dictionary+ দিয়ে শুরু করুন lock, এবং পরে ConcurrentDictionaryএই বিকল্পটি কার্যকর যদি কার্যকর হয় তবে পারফরম্যান্স অপটিমাইজেশন হিসাবে আপগ্রেড করার বিকল্পটি রাখুন। অনেক ক্ষেত্রে তা হবে না।


0

আমরা ক্যাশে সংগ্রহের জন্য ConcurrentDictionary, যে প্রতি 1 ঘন্টা পুনরায় জনবহুল এবং তারপর একাধিক ক্লায়েন্ট থ্রেড দ্বারা পড়া, অনুরূপ ব্যবহার করেছি সমাধান জন্য এই উদাহরণে থ্রেড কি নিরাপদ?প্রশ্ন।

আমরা পেয়েছি, এটি কেবলমাত্র ReadOnlyD অভিধান এ পরিবর্তন করা   সামগ্রিক কর্মক্ষমতা উন্নত করেছে।


রিডইনলিডিয়েশনারি হ'ল অন্য আইডিকোরিয়ালের চারদিকে কেবল মোড়ক। আপনি ফণা নীচে কি ব্যবহার করবেন?
Lu55

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