সি # অবজেক্ট পুলিং প্যাটার্ন বাস্তবায়ন


165

এসকিএল সংযোগ পুলিংয়ের শিরাতে সীমিত সংস্থার জন্য একটি ভাগ করে নেওয়া অবজেক্ট পুল কৌশল বাস্তবায়নের জন্য কি কারও ভাল সংস্থান রয়েছে? (যেমন পুরোপুরি প্রয়োগ করা হবে যে এটি থ্রেড নিরাপদ)।

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

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

আশা করি যে ব্যাকগ্রাউন্ডটি কিছু মূল্য দেয় তবে সরাসরি আপনার কিছু প্রশ্নের উত্তর দেয়:

প্রশ্ন: বস্তুগুলি কি তৈরি করা ব্যয়বহুল?
উত্তর: কোনও বস্তু সীমিত সংস্থার পুল নয়

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

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

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

প্রশ্ন: অগ্রাধিকার, অলস বনাম আগ্রহী লোডিং ইত্যাদির মতো বিষয় সম্পর্কে কী বলা যায়?
উত্তর: সরলতার জন্য কোনও অগ্রাধিকার জড়িত নেই, কেবলমাত্র ধরে নেওয়া যায় যে পুলটি তৈরির সময় আমি উপলভ্য বস্তুর পুলটি তৈরি করব।


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

ক্রিস - কেবল আপনার ২ য় এবং ৩ য় অনুচ্ছেদটি দেখছেন এবং ভাবছেন যে এই সেশনগুলি সত্যই অনির্দিষ্টকালের জন্য বেঁচে রাখা উচিত? মনে হচ্ছে এটি আপনার পরিষেবা সরবরাহকারী পছন্দ করে না (দীর্ঘকালীন চলমান সেশনগুলি), এবং তাই আপনি সম্ভবত একটি পুল বাস্তবায়ন খুঁজছেন যা নতুন সেশনগুলি প্রয়োজনীয় হিসাবে স্পিন করে এবং ব্যবহার না করার সময় সেগুলি বন্ধ করে দেয় (কিছু নির্দিষ্ট সময়ের পরে) । এটি করা যেতে পারে তবে এটি আরও জটিল, তাই আমি নিশ্চিত করতে চাই।
অ্যারোনআট

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

1
আমি মনে করি আপনার প্রয়োজনের বেশিরভাগ টিপিএল ডেটাফ্লো বাফারব্লক করে।
ব্যয়কারী

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

উত্তর:


59

নেট কোর মধ্যে অবজেক্ট পুলিং

Dotnet কোর বস্তুর পুলিং বেস বর্গ গ্রন্থাগার (বিসিএল) যোগ করা এর একটি বাস্তবায়ন হয়েছে। আপনি এখানে মূল গিটহাব ইস্যুটি পড়তে পারেন এবং সিস্টেম.বফার্সের কোড দেখতে পারেন । বর্তমানে ArrayPoolএকমাত্র প্রকার উপলব্ধ এবং অ্যারে পুল করতে ব্যবহৃত হয়। এখানে একটি সুন্দর ব্লগ পোস্ট আছে

namespace System.Buffers
{
    public abstract class ArrayPool<T>
    {
        public static ArrayPool<T> Shared { get; internal set; }

        public static ArrayPool<T> Create(int maxBufferSize = <number>, int numberOfBuffers = <number>);

        public T[] Rent(int size);

        public T[] Enlarge(T[] buffer, int newSize, bool clearBuffer = false);

        public void Return(T[] buffer, bool clearBuffer = false);
    }
}

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

মাইক্রোসফ্ট রোজলিন সি # সংকলকটিতে অবজেক্ট পুলিং

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

1 - শেয়ারডপুলস - বিগডেফাল্ট ব্যবহৃত হয় তবে 20 টি বস্তুর বা 100 টির একটি পুল সঞ্চয় করে।

// Example 1 - In a using statement, so the object gets freed at the end.
using (PooledObject<Foo> pooledObject = SharedPools.Default<List<Foo>>().GetPooledObject())
{
    // Do something with pooledObject.Object
}

// Example 2 - No using statement so you need to be sure no exceptions are not thrown.
List<Foo> list = SharedPools.Default<List<Foo>>().AllocateAndClear();
// Do something with list
SharedPools.Default<List<Foo>>().Free(list);

// Example 3 - I have also seen this variation of the above pattern, which ends up the same as Example 1, except Example 1 seems to create a new instance of the IDisposable [PooledObject<T>][4] object. This is probably the preferred option if you want fewer GC's.
List<Foo> list = SharedPools.Default<List<Foo>>().AllocateAndClear();
try
{
    // Do something with list
}
finally
{
    SharedPools.Default<List<Foo>>().Free(list);
}

2 - লিস্টপুল এবং স্ট্রিংবিল্ডারপুল - তালিকাভুক্ত এবং স্ট্রিংবিল্ডারের জন্য উপরে উল্লিখিত শেয়ারডপুলগুলি বাস্তবায়নের চারপাশে কঠোরভাবে পৃথক বাস্তবায়ন নয়, তবে মোড়কে আলাদা করুন। সুতরাং এইটি শেয়ারডপুলগুলিতে সঞ্চিত বস্তুর পুলটিকে পুনরায় ব্যবহার করে।

// Example 1 - No using statement so you need to be sure no exceptions are thrown.
StringBuilder stringBuilder= StringBuilderPool.Allocate();
// Do something with stringBuilder
StringBuilderPool.Free(stringBuilder);

// Example 2 - Safer version of Example 1.
StringBuilder stringBuilder= StringBuilderPool.Allocate();
try
{
    // Do something with stringBuilder
}
finally
{
    StringBuilderPool.Free(stringBuilder);
}

3 - পুলডডিয়েশনারি এবং পুলড্যাশশেট - এগুলি সরাসরি অবজেক্টপুল ব্যবহার করে এবং সামগ্রীর পৃথক পৃথক পুল রয়েছে। 128 অবজেক্টের একটি পুল সঞ্চয় করে।

// Example 1
PooledHashSet<Foo> hashSet = PooledHashSet<Foo>.GetInstance()
// Do something with hashSet.
hashSet.Free();

// Example 2 - Safer version of Example 1.
PooledHashSet<Foo> hashSet = PooledHashSet<Foo>.GetInstance()
try
{
    // Do something with hashSet.
}
finally
{
    hashSet.Free();
}

Microsoft.IO.RecyclableMemoryStream

এই গ্রন্থাগারটি MemoryStreamবস্তুর জন্য পুলিং সরবরাহ করে। এটি একটি ড্রপ-ইন প্রতিস্থাপন System.IO.MemoryStream। এর ঠিক একই শব্দার্থক শব্দ রয়েছে। এটি বিং ইঞ্জিনিয়াররা ডিজাইন করেছিলেন। ব্লগ পোস্টটি এখানে পড়ুন বা গিটহাবের কোডটি দেখুন ।

var sourceBuffer = new byte[]{0,1,2,3,4,5,6,7}; 
var manager = new RecyclableMemoryStreamManager(); 
using (var stream = manager.GetStream()) 
{ 
    stream.Write(sourceBuffer, 0, sourceBuffer.Length); 
}

নোটটি RecyclableMemoryStreamManagerএকবার ঘোষণা করা উচিত এবং এটি পুরো প্রক্রিয়াটির জন্যই বেঁচে থাকবে – এটি পুল। আপনার ইচ্ছা থাকলে একাধিক পুল ব্যবহার করা পুরোপুরি ঠিক।


2
এটি একটি দুর্দান্ত উত্তর। সি # 6 এবং ভিএস2015 আরটিএম হওয়ার পরে আমি সম্ভবত এটির অনুমোদিত উত্তরটি তৈরি করবো কারণ এটি রোজেন নিজেই এর টিউন করে রাখলে এটি স্পষ্টতই সেরা।
ক্রিস মেরিসিক

আমি সম্মত তবে কোন প্রয়োগ আপনি ব্যবহার করবেন? রোজলিনে তিনটি রয়েছে। উত্তরে আমার প্রশ্নের লিঙ্কটি দেখুন।
মুহাম্মদ রেহান সাইদ

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

1
@ মুহাম্মদরেহানসেইদ অ্যারেপুলের সাথে দুর্দান্ত সংযোজন করেছেন
ক্রিস মেরিসিক

1
এটি RecyclableMemoryStreamঅতি উচ্চ কার্যকারিতা অপ্টিমাইজেশনের জন্য একটি আশ্চর্যজনক সংযোজন দেখে ।
ক্রিস মেরিসিক

315

একাধিক অজানা কারণে এই প্রশ্নটি যতটা আশা করা যায় তার চেয়ে একটু জটিল: পুল, সংযোগ পুল ইত্যাদি - কারণ যখন আপনি জানেন যে উত্সটি ঠিক কী করে এবং কীভাবে সেই সংস্থানটি কীভাবে কার্যকর হয় তার উপর নিয়ন্ত্রণ আরো গুরুত্বপূর্ণ তখন একটিটিকে অনুকূলকরণ করা সহজ ।

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

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

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

রিসোর্স লোডিং প্রক্রিয়াটির জন্য,। নেট ইতিমধ্যে আমাদের একটি পরিষ্কার বিমূর্ততা দেয় - প্রতিনিধিরা।

private Func<Pool<T>, T> factory;

এটি পুলের কনস্ট্রাক্টরের মাধ্যমে পাস করুন এবং আমরা এটি শেষ করেছি। new()সীমাবদ্ধতার সাথে জেনেরিক টাইপ ব্যবহার করাও খুব কার্যকর, তবে এটি আরও নমনীয়।


অন্য দুটি পরামিতিগুলির মধ্যে অ্যাক্সেস কৌশলটি আরও জটিল জন্তু, সুতরাং আমার পন্থাটি ছিল উত্তরাধিকার (ইন্টারফেস) ভিত্তিক পদ্ধতির ব্যবহার:

public class Pool<T> : IDisposable
{
    // Other code - we'll come back to this

    interface IItemStore
    {
        T Fetch();
        void Store(T item);
        int Count { get; }
    }
}

এখানে ধারণাটি সহজ - আমরা পাবলিক Poolক্লাসকে থ্রেড-সুরক্ষার মতো সাধারণ সমস্যাগুলি পরিচালনা করতে দেব , তবে প্রতিটি অ্যাক্সেস প্যাটার্নের জন্য আলাদা "আইটেম স্টোর" ব্যবহার করব। লিফো সহজেই একটি স্ট্যাক দ্বারা প্রতিনিধিত্ব করা হয়, ফিফো একটি সারি এবং আমি List<T>একটি রাউন্ড-রবিন অ্যাক্সেস প্যাটার্নটিকে আনুমানিকভাবে আন এবং ইনডেক্স পয়েন্টার ব্যবহার করে খুব বেশি-অনুকূল-না-তবে-সম্ভবত-পর্যাপ্ত বৃত্তাকার বাফার বাস্তবায়ন ব্যবহার করেছি ।

নীচের সমস্ত ক্লাসের অভ্যন্তর শ্রেণি Pool<T>- এটি একটি স্টাইল পছন্দ ছিল, তবে যেহেতু এগুলি সত্যই বাইরের বাইরে ব্যবহার করা নয় Pool, তাই এটি সবচেয়ে বেশি অর্থবোধ করে।

    class QueueStore : Queue<T>, IItemStore
    {
        public QueueStore(int capacity) : base(capacity)
        {
        }

        public T Fetch()
        {
            return Dequeue();
        }

        public void Store(T item)
        {
            Enqueue(item);
        }
    }

    class StackStore : Stack<T>, IItemStore
    {
        public StackStore(int capacity) : base(capacity)
        {
        }

        public T Fetch()
        {
            return Pop();
        }

        public void Store(T item)
        {
            Push(item);
        }
    }

এগুলি হ'ল সুস্পষ্ট - স্ট্যাক এবং সারি। আমি মনে করি না যে তারা সত্যিকার অর্থে খুব বেশি ব্যাখ্যা দেয় warrant বিজ্ঞপ্তি বাফারটি আরও জটিল:

    class CircularStore : IItemStore
    {
        private List<Slot> slots;
        private int freeSlotCount;
        private int position = -1;

        public CircularStore(int capacity)
        {
            slots = new List<Slot>(capacity);
        }

        public T Fetch()
        {
            if (Count == 0)
                throw new InvalidOperationException("The buffer is empty.");

            int startPosition = position;
            do
            {
                Advance();
                Slot slot = slots[position];
                if (!slot.IsInUse)
                {
                    slot.IsInUse = true;
                    --freeSlotCount;
                    return slot.Item;
                }
            } while (startPosition != position);
            throw new InvalidOperationException("No free slots.");
        }

        public void Store(T item)
        {
            Slot slot = slots.Find(s => object.Equals(s.Item, item));
            if (slot == null)
            {
                slot = new Slot(item);
                slots.Add(slot);
            }
            slot.IsInUse = false;
            ++freeSlotCount;
        }

        public int Count
        {
            get { return freeSlotCount; }
        }

        private void Advance()
        {
            position = (position + 1) % slots.Count;
        }

        class Slot
        {
            public Slot(T item)
            {
                this.Item = item;
            }

            public T Item { get; private set; }
            public bool IsInUse { get; set; }
        }
    }

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

মনে রাখবেন, এই ক্লাসগুলি ব্যক্তিগত অভ্যন্তর শ্রেণি - সে কারণেই তাদের পুরো ত্রুটি-পরীক্ষার প্রয়োজন হয় না, পুল নিজেই এগুলিতে অ্যাক্সেসকে সীমাবদ্ধ করে।

একটি গণনা এবং একটি কারখানা পদ্ধতি নিক্ষেপ করুন এবং আমরা এই অংশটি সম্পন্ন করেছি:

// Outside the pool
public enum AccessMode { FIFO, LIFO, Circular };

    private IItemStore itemStore;

    // Inside the Pool
    private IItemStore CreateItemStore(AccessMode mode, int capacity)
    {
        switch (mode)
        {
            case AccessMode.FIFO:
                return new QueueStore(capacity);
            case AccessMode.LIFO:
                return new StackStore(capacity);
            default:
                Debug.Assert(mode == AccessMode.Circular,
                    "Invalid AccessMode in CreateItemStore");
                return new CircularStore(capacity);
        }
    }

সমাধানের পরবর্তী সমস্যা হ'ল লোডিং কৌশল। আমি তিন ধরণের সংজ্ঞা দিয়েছি:

public enum LoadingMode { Eager, Lazy, LazyExpanding };

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

লোডিং পদ্ধতিগুলি আসলে খুব জটিল নয়, এখন আমাদের আইটেম-স্টোর বিমূর্ততা রয়েছে:

    private int size;
    private int count;

    private T AcquireEager()
    {
        lock (itemStore)
        {
            return itemStore.Fetch();
        }
    }

    private T AcquireLazy()
    {
        lock (itemStore)
        {
            if (itemStore.Count > 0)
            {
                return itemStore.Fetch();
            }
        }
        Interlocked.Increment(ref count);
        return factory(this);
    }

    private T AcquireLazyExpanding()
    {
        bool shouldExpand = false;
        if (count < size)
        {
            int newCount = Interlocked.Increment(ref count);
            if (newCount <= size)
            {
                shouldExpand = true;
            }
            else
            {
                // Another thread took the last spot - use the store instead
                Interlocked.Decrement(ref count);
            }
        }
        if (shouldExpand)
        {
            return factory(this);
        }
        else
        {
            lock (itemStore)
            {
                return itemStore.Fetch();
            }
        }
    }

    private void PreloadItems()
    {
        for (int i = 0; i < size; i++)
        {
            T item = factory(this);
            itemStore.Store(item);
        }
        count = size;
    }

sizeএবং countক্ষেত্র উপরে এবং পুকুর সর্বাধিক মাপ পুকুর (কিন্তু অগত্যা মালিকানাধীন সম্পদের মোট সংখ্যা পড়ুন প্রাপ্তিসাধ্য যথাক্রমে)। AcquireEagerসবচেয়ে সহজ, এটি ধরে নেওয়া হয় যে কোনও আইটেম ইতিমধ্যে দোকানে রয়েছে - এই আইটেমগুলি নির্মাণে প্রিলোড করা হবে, অর্থাৎ PreloadItemsশেষ দেখানো পদ্ধতিতে।

AcquireLazyপুলটিতে নিখরচায় আইটেম রয়েছে কিনা তা পরীক্ষা করে দেখুন এবং তা না থাকলে এটি একটি নতুন তৈরি করে। AcquireLazyExpandingপুলটি এখনও তার টার্গেটের আকারে না পৌঁছলে একটি নতুন সংস্থান তৈরি করবে। আমি লকিং কমাতে এটিকে অপ্টিমাইজ করার চেষ্টা করেছি এবং আমি আশা করি যে আমি কোনও ভুল করিনি (আমি বহু-থ্রেডেড শর্তে এটি পরীক্ষা করেছি , তবে স্পষ্টতই পরিস্ফুটিত হয়নি)।

আপনি ভাবছেন যে কেন এই পদ্ধতির কোনওটিই কেন সর্বাধিক আকারে পৌঁছেছে কিনা তা পরীক্ষা করে দেখার বিরক্ত করে না। আমি এক মুহূর্তের মধ্যে এটি পেতে হবে।


এখন পুলের জন্য এখানে ব্যক্তিগত ডেটার পুরো সেট রয়েছে, যার মধ্যে কয়েকটি ইতিমধ্যে প্রদর্শিত হয়েছে:

    private bool isDisposed;
    private Func<Pool<T>, T> factory;
    private LoadingMode loadingMode;
    private IItemStore itemStore;
    private int size;
    private int count;
    private Semaphore sync;

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

কনস্ট্রাক্টর এর মত দেখাচ্ছে:

    public Pool(int size, Func<Pool<T>, T> factory,
        LoadingMode loadingMode, AccessMode accessMode)
    {
        if (size <= 0)
            throw new ArgumentOutOfRangeException("size", size,
                "Argument 'size' must be greater than zero.");
        if (factory == null)
            throw new ArgumentNullException("factory");

        this.size = size;
        this.factory = factory;
        sync = new Semaphore(size, size);
        this.loadingMode = loadingMode;
        this.itemStore = CreateItemStore(accessMode, size);
        if (loadingMode == LoadingMode.Eager)
        {
            PreloadItems();
        }
    }

এখানে কোন আশ্চর্য হওয়া উচিত। PreloadItemsইতিমধ্যে কেবল দেখানো পদ্ধতিটি আগ্রহী লোডিংয়ের জন্য বিশেষ-আবরণ ।

যেহেতু প্রায় সব কিছু পরিষ্কারভাবে বিমূর্ত হয়ে গেছে এখন, আসল Acquireএবং Releaseপদ্ধতিগুলি সত্যিই খুব সোজা:

    public T Acquire()
    {
        sync.WaitOne();
        switch (loadingMode)
        {
            case LoadingMode.Eager:
                return AcquireEager();
            case LoadingMode.Lazy:
                return AcquireLazy();
            default:
                Debug.Assert(loadingMode == LoadingMode.LazyExpanding,
                    "Unknown LoadingMode encountered in Acquire method.");
                return AcquireLazyExpanding();
        }
    }

    public void Release(T item)
    {
        lock (itemStore)
        {
            itemStore.Store(item);
        }
        sync.Release();
    }

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

সর্বশেষে তবে অন্তত পরিষ্কার নয়:

    public void Dispose()
    {
        if (isDisposed)
        {
            return;
        }
        isDisposed = true;
        if (typeof(IDisposable).IsAssignableFrom(typeof(T)))
        {
            lock (itemStore)
            {
                while (itemStore.Count > 0)
                {
                    IDisposable disposable = (IDisposable)itemStore.Fetch();
                    disposable.Dispose();
                }
            }
        }
        sync.Close();
    }

    public bool IsDisposed
    {
        get { return isDisposed; }
    }

এই IsDisposedসম্পত্তিটির উদ্দেশ্য এক মুহুর্তে পরিষ্কার হয়ে যাবে। সমস্ত মূল Disposeপদ্ধতি যা বাস্তবায়িত করে তা হ'ল আসল পোল্ড আইটেমগুলি প্রয়োগ করে তবে তা নিষ্পত্তি করা IDisposable


এখন আপনি মূলত এটিকে হ'ল একটি try-finallyব্লক সহ ব্যবহার করতে পারেন , তবে আমি সেই বাক্য গঠনটি পছন্দ করি না, কারণ আপনি যদি ক্লাস এবং পদ্ধতির মধ্যে পুলের উত্সগুলি অতিক্রম করতে শুরু করেন তবে এটি খুব বিভ্রান্ত হতে চলেছে। এটা যে প্রধান বর্গ একটি সম্পদ ব্যবহার করে এমনকি নেই সম্ভব আছে পুকুর একটি রেফারেন্স। এটি সত্যিই বেশ অগোছালো হয়ে যায়, সুতরাং একটি "স্মার্ট" পুলযুক্ত অবজেক্ট তৈরি করা আরও ভাল পদ্ধতির।

ধরা যাক আমরা নিম্নলিখিত সাধারণ ইন্টারফেস / শ্রেণি দিয়ে শুরু করি:

public interface IFoo : IDisposable
{
    void Test();
}

public class Foo : IFoo
{
    private static int count = 0;

    private int num;

    public Foo()
    {
        num = Interlocked.Increment(ref count);
    }

    public void Dispose()
    {
        Console.WriteLine("Goodbye from Foo #{0}", num);
    }

    public void Test()
    {
        Console.WriteLine("Hello from Foo #{0}", num);
    }
}

এখানে আমাদের প্রতারক নিষ্পত্তিযোগ্য Fooসংস্থান যা IFooঅনন্য পরিচয় উত্পন্ন করার জন্য কিছু বয়লারপ্লেট কোড প্রয়োগ করে এবং রয়েছে। আমরা যা করি তা হ'ল আরেকটি বিশেষ, পুলড অবজেক্ট তৈরি করা:

public class PooledFoo : IFoo
{
    private Foo internalFoo;
    private Pool<IFoo> pool;

    public PooledFoo(Pool<IFoo> pool)
    {
        if (pool == null)
            throw new ArgumentNullException("pool");

        this.pool = pool;
        this.internalFoo = new Foo();
    }

    public void Dispose()
    {
        if (pool.IsDisposed)
        {
            internalFoo.Dispose();
        }
        else
        {
            pool.Release(this);
        }
    }

    public void Test()
    {
        internalFoo.Test();
    }
}

এটি কেবলমাত্র তার "অভ্যন্তরীণ" সমস্ত বাস্তব পদ্ধতির প্রক্সি করে IFoo(আমরা ক্যাসলের মতো ডায়নামিক প্রক্সি লাইব্রেরি দিয়ে এটি করতে পারি, তবে আমি তাতে প্রবেশ করব না)। এটি Poolযেটিকে এটি তৈরি করে তার একটি রেফারেন্সও বজায় রাখে , যাতে আমরা যখন Disposeএই বস্তুটি করি তখন এটি স্বয়ংক্রিয়ভাবে পুলটিতে ফিরে আসে। ব্যতীত যখন পুকুর ইতিমধ্যে বিন্যস্ত হয়েছে - এই উপায়ে আমরা "পরিষ্করণ" মোডে এবং এই ক্ষেত্রে এটা আসলে হয় অভ্যন্তরীণ সম্পদ আপ সাফ করে পরিবর্তে।


উপরের পদ্ধতির ব্যবহার করে, আমরা এই জাতীয় কোড লিখতে পাই:

// Create the pool early
Pool<IFoo> pool = new Pool<IFoo>(PoolSize, p => new PooledFoo(p),
    LoadingMode.Lazy, AccessMode.Circular);

// Sometime later on...
using (IFoo foo = pool.Acquire())
{
    foo.Test();
}

এটি করতে পারা খুব ভাল জিনিস। এর মানে যে কোড যা ব্যবহারIFoo (যেমন কোড যা সৃষ্টি থেকে ভিন্ন) আসলে পুকুর সচেতন হতে হবে দরকার নেই। এমনকি আপনি আপনার প্রিয় ডিআই লাইব্রেরি এবং সরবরাহকারী / কারখানা হিসাবে অবজেক্টগুলি ইনজেক্ট করতে পারেন ।IFooPool<T>


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

আপনার যদি এর কোনও সম্পর্কে কোনও প্রশ্ন বা উদ্বেগ থাকে তবে আমাকে জানান।


62
আমি এসও পড়েছি এমন একটি সম্পূর্ণ, সহায়ক এবং আকর্ষণীয় উত্তর।
জোশ স্মিটন

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

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

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

5
খুব চিত্তাকর্ষক, যদিও বেশিরভাগ পরিস্থিতিতে কিছুটা প্রকৌশলী। আমি আশা করি এটির মতো কোনও কাঠামোর অংশ হবে।
কেওসপ্যান্ডিয়ন

7

এর মতো কিছু আপনার প্রয়োজন অনুসারে করতে পারে।

/// <summary>
/// Represents a pool of objects with a size limit.
/// </summary>
/// <typeparam name="T">The type of object in the pool.</typeparam>
public sealed class ObjectPool<T> : IDisposable
    where T : new()
{
    private readonly int size;
    private readonly object locker;
    private readonly Queue<T> queue;
    private int count;


    /// <summary>
    /// Initializes a new instance of the ObjectPool class.
    /// </summary>
    /// <param name="size">The size of the object pool.</param>
    public ObjectPool(int size)
    {
        if (size <= 0)
        {
            const string message = "The size of the pool must be greater than zero.";
            throw new ArgumentOutOfRangeException("size", size, message);
        }

        this.size = size;
        locker = new object();
        queue = new Queue<T>();
    }


    /// <summary>
    /// Retrieves an item from the pool. 
    /// </summary>
    /// <returns>The item retrieved from the pool.</returns>
    public T Get()
    {
        lock (locker)
        {
            if (queue.Count > 0)
            {
                return queue.Dequeue();
            }

            count++;
            return new T();
        }
    }

    /// <summary>
    /// Places an item in the pool.
    /// </summary>
    /// <param name="item">The item to place to the pool.</param>
    public void Put(T item)
    {
        lock (locker)
        {
            if (count < size)
            {
                queue.Enqueue(item);
            }
            else
            {
                using (item as IDisposable)
                {
                    count--;
                }
            }
        }
    }

    /// <summary>
    /// Disposes of items in the pool that implement IDisposable.
    /// </summary>
    public void Dispose()
    {
        lock (locker)
        {
            count = 0;
            while (queue.Count > 0)
            {
                using (queue.Dequeue() as IDisposable)
                {

                }
            }
        }
    }
}

ব্যবহারের উদাহরণ

public class ThisObject
{
    private readonly ObjectPool<That> pool = new ObjectPool<That>(100);

    public void ThisMethod()
    {
        var that = pool.Get();

        try
        { 
            // Use that ....
        }
        finally
        {
            pool.Put(that);
        }
    }
}

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

1
@ অ্যারোনট - এটি কি আসলেই অদ্ভুত? আমি একটি হালকা ওজনের পুল তৈরি করতে চেয়েছিলাম যা কেবলমাত্র কার্যকারিতা প্রয়োজন offers ক্লাসটি সঠিকভাবে ব্যবহার করা ক্লায়েন্টের উপর নির্ভর করে।
কেওসপ্যান্ডিয়ন

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

1
এটা কি অচলভাবে পড়তে হবে? তবে আমার কাছে এটি অদ্ভুত বলে মনে হচ্ছে যে আপনি অবশেষে বিবৃতিটির ভিতরে রাখবেন, যদি এর ব্যতিক্রম হয় তবে তা কি অবজেক্ট হবে না যে তার নিজের বস্তুটি দোষযুক্ত? আপনি কি সেই Putপদ্ধতির অভ্যন্তরে এটি পরিচালনা করতে পারবেন এবং কিছুটা সরলতার জন্য অবজেক্টটি ত্রুটিযুক্ত কিনা তা যাচাই করার জন্য এবং পূর্ববর্তীটি সন্নিবেশ করার পরিবর্তে পুলটিতে যুক্ত করার জন্য একটি নতুন উদাহরণ তৈরি করবেন?
ক্রিস মেরিসিক

1
@ ক্রিস - আমি কেবল একটি সহজ সরঞ্জাম সরবরাহ করছি যা আমি অতীতে দরকারী বলে মনে করেছি। বাকিটা আপনার উপর. আপনি উপযুক্ত হিসাবে কোডটি পরিবর্তন করুন এবং ব্যবহার করুন।
কেওসপ্যান্ডিয়ন

6

এই লিঙ্কের জন্য ধন্যবাদ। এই বাস্তবায়নের জন্য কোনও আকারের সীমা নেই, সুতরাং যদি আপনার অবজেক্ট তৈরিতে স্পাইক থাকে তবে inst দৃষ্টান্তগুলি কখনই সংগ্রহ করা হবে না এবং অন্য স্পাইক না হওয়া পর্যন্ত সম্ভবত কখনও ব্যবহার করা হবে না। এটি যদিও খুব সহজ এবং সহজেই বোঝা যায় তবে সর্বাধিক আকারের সীমা যুক্ত করা শক্ত হবে না।
মুহাম্মদ রেহান সা Saeedদ

দুর্দান্ত এবং সহজ
ড্যানিয়েল ডি জাওয়ান

4

সেদিন ফিরে মাইক্রোসফ্ট মাইক্রোসফ্ট ট্রানজেকশন সার্ভার (এমটিএস) এবং পরে সিওএম অবজেক্টগুলির জন্য অবজেক্ট পুলিংয়ের জন্য সিওএম + এর মাধ্যমে একটি কাঠামো সরবরাহ করেছিল। এই কার্যকারিতাটি .NET ফ্রেমওয়ার্ক এবং এখন উইন্ডোজ যোগাযোগ ফাউন্ডেশনে সিস্টেম.এন্টারপ্রাইজ সার্ভিসগুলিতে এগিয়ে নেওয়া হয়েছিল।

ডাব্লুসিএফ-তে অবজেক্ট পুলিং

এই নিবন্ধটি .NET 1.1 থেকে এসেছে তবে ফ্রেমওয়ার্কের বর্তমান সংস্করণগুলিতে এখনও প্রয়োগ করা উচিত (যদিও ডাব্লুসিএফ পছন্দসই পদ্ধতি)।

অবজেক্ট পুলিং। নেট


আমাকে দেখানোর জন্য +1 হ'ল IInstanceProviderইন্টারফেসটি বিদ্যমান কারণ আমি এটি আমার সমাধানের জন্য প্রয়োগ করব। মাইক্রোসফ্ট সরবরাহ করা ইন্টারফেসের পিছনে আমার কোডগুলি স্ট্যাকিংয়ের পক্ষে আমি যখনই একটি অনুরাগী যখন তারা কোনও উপযুক্ত সংজ্ঞা সরবরাহ করে।
ক্রিস মেরিসিক

4

আমি সত্যই অরনউটের প্রয়োগ বাস্তবায়ন পছন্দ করি - বিশেষত যেহেতু সেগুলি সেমফোর ব্যবহারের মাধ্যমে উপলভ্য হওয়ার জন্য উত্সের অপেক্ষার বিষয়টি পরিচালনা করে। আমি আরও কিছু সংযোজন করতে চাই:

  1. পদ্ধতিতে প্যারামিটার হিসাবে সময়সীমাটি পরিবর্তন sync.WaitOne()করুন sync.WaitOne(timeout)এবং প্রকাশ করুন Acquire(int timeout)। থ্রেডের সময়টি কোনও অবজেক্টের জন্য অপেক্ষা করার সময় কালের শর্তটি পরিচালনা করাও প্রয়োজন।
  2. Recycle(T item)কোনও ব্যর্থতা দেখা দিলে যখন কোনও বস্তুর পুনর্ব্যবহার করা দরকার তখন পরিস্থিতিগুলি পরিচালনা করতে পদ্ধতি যুক্ত করুন for

3

এটি পুলে সীমিত সংখ্যক অবজেক্ট সহ আরও একটি বাস্তবায়ন।

public class ObjectPool<T>
    where T : class
{
    private readonly int maxSize;
    private Func<T> constructor;
    private int currentSize;
    private Queue<T> pool;
    private AutoResetEvent poolReleasedEvent;

    public ObjectPool(int maxSize, Func<T> constructor)
    {
        this.maxSize = maxSize;
        this.constructor = constructor;
        this.currentSize = 0;
        this.pool = new Queue<T>();
        this.poolReleasedEvent = new AutoResetEvent(false);
    }

    public T GetFromPool()
    {
        T item = null;
        do
        {
            lock (this)
            {
                if (this.pool.Count == 0)
                {
                    if (this.currentSize < this.maxSize)
                    {
                        item = this.constructor();
                        this.currentSize++;
                    }
                }
                else
                {
                    item = this.pool.Dequeue();
                }
            }

            if (null == item)
            {
                this.poolReleasedEvent.WaitOne();
            }
        }
        while (null == item);
        return item;
    }

    public void ReturnToPool(T item)
    {
        lock (this)
        {
            this.pool.Enqueue(item);
            this.poolReleasedEvent.Set();
        }
    }
}

3

জাভা ওরিয়েন্টেড, এই নিবন্ধটি সংযোগআইপুল পুলের প্যাটার্ন এবং বিমূর্ত বস্তুর পুলের প্যাটার্নটি প্রকাশ করে এবং এটি প্রথম প্রথম পদ্ধতির হতে পারে: http://www.developer.com/design/article.php/626171/Pattern-Summaries-Object- পুল ool পেজটি

অবজেক্ট পুল প্যাটার্ন:

প্যাটার্ন



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