এখানে BlockingCollection
প্রচুর নিখুঁত বৈশিষ্ট্য সহ অপেক্ষারত সমর্থন করে এমন একটি প্রাথমিক বুনিয়াদ বাস্তবায়ন । এটি AsyncEnumerable
লাইব্রেরিটি ব্যবহার করে , এটি 8.0-র চেয়ে পুরানো সি # সংস্করণের জন্য অ্যাসিঙ্ক্রোনাস গণনা সম্ভব করে তোলে।
public class AsyncBlockingCollection<T>
{
private Queue<T> _queue = new Queue<T>();
private SemaphoreSlim _semaphore = new SemaphoreSlim(0);
private int _consumersCount = 0;
private bool _isAddingCompleted;
public void Add(T item)
{
lock (_queue)
{
if (_isAddingCompleted) throw new InvalidOperationException();
_queue.Enqueue(item);
}
_semaphore.Release();
}
public void CompleteAdding()
{
lock (_queue)
{
if (_isAddingCompleted) return;
_isAddingCompleted = true;
if (_consumersCount > 0) _semaphore.Release(_consumersCount);
}
}
public IAsyncEnumerable<T> GetConsumingEnumerable()
{
lock (_queue) _consumersCount++;
return new AsyncEnumerable<T>(async yield =>
{
while (true)
{
lock (_queue)
{
if (_queue.Count == 0 && _isAddingCompleted) break;
}
await _semaphore.WaitAsync();
bool hasItem;
T item = default;
lock (_queue)
{
hasItem = _queue.Count > 0;
if (hasItem) item = _queue.Dequeue();
}
if (hasItem) await yield.ReturnAsync(item);
}
});
}
}
ব্যবহারের উদাহরণ:
var abc = new AsyncBlockingCollection<int>();
var producer = Task.Run(async () =>
{
for (int i = 1; i <= 10; i++)
{
await Task.Delay(100);
abc.Add(i);
}
abc.CompleteAdding();
});
var consumer = Task.Run(async () =>
{
await abc.GetConsumingEnumerable().ForEachAsync(async item =>
{
await Task.Delay(200);
await Console.Out.WriteAsync(item + " ");
});
});
await Task.WhenAll(producer, consumer);
আউটপুট:
1 2 3 4 5 6 7 8 9 10
আপডেট: সি # 8 প্রকাশের সাথে সাথে, অ্যাসিঙ্ক্রোনাস গণনা একটি বিল্ট-ইন ভাষার বৈশিষ্ট্য হয়ে উঠেছে। প্রয়োজনীয় ক্লাসগুলি ( IAsyncEnumerable
, IAsyncEnumerator
)। নেট কোর 3.0.০ এ এম্বেড করা হয় এবং। নেট ফ্রেমওয়ার্ক ৪.6.১+ ( মাইক্রোসফট.বিসিএল.এসিএনসিআইন্টারনেস ) এর জন্য প্যাকেজ হিসাবে দেওয়া হয় ।
GetConsumingEnumerable
নতুন সি # 8 সিনট্যাক্সের বৈশিষ্ট্যযুক্ত এখানে একটি বিকল্প বাস্তবায়ন রয়েছে:
public async IAsyncEnumerable<T> GetConsumingEnumerable()
{
lock (_queue) _consumersCount++;
while (true)
{
lock (_queue)
{
if (_queue.Count == 0 && _isAddingCompleted) break;
}
await _semaphore.WaitAsync();
bool hasItem;
T item = default;
lock (_queue)
{
hasItem = _queue.Count > 0;
if (hasItem) item = _queue.Dequeue();
}
if (hasItem) yield return item;
}
}
একই পদ্ধতিতে await
এবং সহাবস্থানটি নোট করুন yield
।
ব্যবহারের উদাহরণ (সি # 8):
var consumer = Task.Run(async () =>
{
await foreach (var item in abc.GetConsumingEnumerable())
{
await Task.Delay(200);
await Console.Out.WriteAsync(item + " ");
}
});
await
আগে নোট করুন foreach
।
await Task.Run(() => blockingCollection.Take())
টাস্কটি ব্যবহার করেন তবে অন্য থ্রেডে সঞ্চালিত হবে এবং আপনার ইউআই থ্রেডটি ব্লক হবে না I কথাটি না?