[英]How to implement a sorted buffer?
I need to traverse a collection of disjoint folders;我需要遍历一组不相交的文件夹; each folder is associated to a visited time configurated somewhere in the folder.
每个文件夹都与文件夹中某处配置的访问时间相关联。
I then sort the folders, and process the one with the earliest visited time first.然后我对文件夹进行排序,首先处理访问时间最早的文件夹。 Note the processing is generally slower than the traversing.
请注意,处理通常比遍历慢。
My code targets Framework4.8.1;我的代码针对Framework4.8.1; Currently my implementation is as follows:
目前我的实现如下:
public class BySeparateThread
{
ConcurrentDictionary<string, DateTime?> _dict = new ConcurrentDictionary<string, DateTime?>();
private object _lock;
/// <summary>
/// this will be called by producer thread;
/// </summary>
/// <param name="address"></param>
/// <param name="time"></param>
public void add(string address,DateTime? time) {
_dict.TryAdd(address, time);
}
/// <summary>
/// called by subscriber thread;
/// </summary>
/// <returns></returns>
public string? next() {
lock (_lock) {
var r = _dict.FirstOrDefault();
//return sortedList.FirstOrDefault().Value;
if (r.Key is null)
{
return r.Key;
}
if (r.Value is null)
{
_dict.TryRemove(r.Key, out var _);
return r.Key;
}
var key = r.Key;
foreach (var item in _dict.Skip(1) )
{
if (item.Value is null)
{
_dict.TryRemove(item.Key, out var _);
return item.Key;
}
if (item.Value< r.Value)
{
r=item;
}
}
_dict.TryRemove(key, out var _);
return key;
}
}
/// <summary>
/// this will be assigned of false by producer thread;
/// </summary>
public bool _notComplete = true;
/// <summary>
/// shared configuration for subscribers;
/// </summary>
fs.addresses_.disjoint.deV_._bak.Io io; //.io_._CfgX.Create(cancel, git)
/// <summary>
/// run this in a separate thread other than <see cref="add(string, DateTime?)"/>
/// </summary>
/// <param name="sln"></param>
/// <returns></returns>
public async Task _asyn_ofAddress(string sln)
{
while (_notComplete)
{
var f = next();
if (f is null )
{
await Task.Delay(30*1000);
//await Task.Yield();
continue;
}
/// degree of concurrency is controlled by a semophore; for instance, at most 4 are tackled:
new dev.srcs.each.sln_.delvable.Bak_srcsInAddresses(io)._startTask_ofAddress(sln);
}
}
}
For the above, I'm concerned about the while(_notComplete)
part, as it looks like there would be many loops doing nothing there.对于上面的内容,我担心
while(_notComplete)
部分,因为看起来会有很多循环在那里什么都不做。 I think there should be better ways to remove the while
by utilizing the fact that the collection can notify whether it's empty or not at some/various stages such as when we add
.我认为应该有更好的方法来删除
while
通过利用集合可以在某些/不同阶段通知它是否为空这一事实,例如当我们add
时。
There would be better implementation which can be based on some mature framework such as those being considered by me these days but I often stopped wondering at some implementation details:会有更好的实现,它可以基于一些成熟的框架,比如这些天我正在考虑的框架,但我经常不再想知道一些实现细节:
Sorting buffered Observables seems similar to my problem; 对缓冲的 Observables 进行排序似乎与我的问题相似; but it ends with a solution similar to the one I currently have but am not satisfied with, as stated in the above.
但它以类似于我目前拥有但不满意的解决方案结束,如上文所述。
Could some one give me a sample code?有人可以给我一个示例代码吗? Please give as concrete code as you can;
请尽可能给出具体的代码; As you can see, I have researched some general ideas/paths and finally what stops me short is the details, which are often glossed over in some docs.
如您所见,我研究了一些一般性的想法/路径,最后让我失望的是细节,这些细节经常在一些文档中被掩盖。
I just found one solution which is better than my current one.我刚刚找到了一种比我目前的解决方案更好的解决方案。 I believe there are some even better ones, so please do post your answers if you find some;
我相信还有一些更好的,所以如果你找到了,请张贴你的答案; my current one is just what I can hack for what I know so far.
我目前的版本正是我目前所知道的可以破解的。
I found Prioritized queues in Task Parallel Library , and I write a similar one for my case:我在 Task Parallel Library 中找到了 Prioritized queues ,我为我的案例写了一个类似的队列:
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reactive.Subjects;
using System.Threading;
using System.Threading.Tasks;
namespace nilnul.dev.srcs.every.slns._bak
{
public class BySortedSet : IProducerConsumerCollection<(string, DateTime)>
{
private class _Comparer : IComparer<(string, DateTime)>
{
public int Compare((string, DateTime) first, (string, DateTime) second)
{
var returnValue = first.Item2.CompareTo(second.Item2);
if (returnValue == 0)
returnValue = first.Item1.CompareTo(second.Item1);
return returnValue;
}
static public _Comparer Singleton
{
get
{
return nilnul._obj.typ_.nilable_.unprimable_.Singleton<_Comparer>.Instance;// just some magic to get an instance
}
}
}
SortedSet<(string, DateTime)> _dict = new SortedSet<(string, DateTime)>(
_Comparer.Singleton
);
private object _lock=new object();
public int Count
{
get
{
lock(_lock){
return _dict.Count;
}
}
}
public object SyncRoot => _lock;
public bool IsSynchronized => true;
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
//throw new NotImplementedException();
}
public void CopyTo((string, DateTime)[] array, int index)
{
lock (_lock)
{
foreach (var item in _dict)
{
array[index++] = item;
}
}
}
public void CopyTo(Array array, int index)
{
lock (_lock)
{
foreach (var item in _dict)
{
array.SetValue(item, index++);
}
}
}
public bool TryAdd((string, DateTime) item)
{
lock (_lock)
{
return _dict.Add(item);
}
}
public bool TryTake(out (string, DateTime) item)
{
lock (_lock)
{
item = _dict.Min;
if (item==default)
{
return false;
}
return _dict.Remove(item);
}
}
public (string, DateTime)[] ToArray()
{
lock (_lock)
{
return this._dict.ToArray();
}
}
public IEnumerator<(string, DateTime)> GetEnumerator()
{
return ToArray().AsEnumerable().GetEnumerator();
}
/// <summary>
/// </summary>
/// <returns></returns>
public BlockingCollection<(string, DateTime)> asBlockingCollection() {
return new BlockingCollection<(string, DateTime)>(
this
);
}
}
}
Then I can use that like:然后我可以像这样使用它:
static public void ExampleUse(CancellationToken cancellationToken) {
var s = new BySortedSet().asBlockingCollection();
/// traversal thread:
s.Add(("", DateTime.MinValue));
//...
s.CompleteAdding();
/// tackler thread:
///
foreach (var item in s.GetConsumingEnumerable(cancellationToken))
{
/// process the item;
/// todo: degree of parallelism is controlled by the tackler, or is there a better way like in dataflow or Rx or sth else?
}
}
Thanks!谢谢!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.