[英]How to enumerate list items randomly in C#?
對於大專家,我有一個具有挑戰性的問題。 這在我的代碼中還沒有實際用法,但來自我剛才的想法。
如果我有一個IList<T>
,我如何實現一個隨機遍歷列表並且可以同時由多個線程使用的枚舉器?
例如,如果我有元素A
, B
, C
, D
, E
, F
和兩個並發線程在列表上執行for-each
循環並且獲取了ReaderLock(所以我確定沒有其他人會觸及列表因此導致例如,我希望它們各自的循環返回,例如, B
, E
, C
, D
, A
, F
和E
, B
, D
, C
, A
, F
。
我需要這個的原因是因為我需要在List<SslStream>
元素上放置鎖以向客戶端發送數據, 因為SslStream不是線程安全的 。 隨機挑選元素(但確保我選擇它們 )可以減少鎖定沖突概率,並且可以提高I / O綁定操作性能。
請記住,即使我告訴你為什么我需要這樣的調查員,我仍然喜歡挑戰。 可以有其他方法將相同的數據發送到多個客戶端,但我的問題仍然是相同的:) :)
像這樣的東西(顯然需要生產):
class RandomList<T> : IEnumerable<T> {
private readonly IList<T> list;
private readonly Random rg;
private readonly object sync = new Object();
public RandomList(IList<T> list) : this(list, new Random()) { }
public RandomList(IList<T> list, Random rg) {
Contract.Requires<ArgumentNullException>(list != null);
Contract.Requires<ArgumentNullException>(rg != null);
this.list = list;
this.rg = rg;
}
public IEnumerator<T> GetEnumerator() {
List<int> indexes;
// Random.Next is not guaranteed to be thread-safe
lock (sync) {
indexes = Enumerable
.Range(0, this.list.Count)
.OrderBy(x => this.rg.Next())
.ToList();
}
foreach (var index in indexes) {
yield return this.list[index];
}
}
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
}
創建一個與列表大小相同的數組,最初將其填充為[i] = i,然后使用Fisher Yates算法進行隨機播放。
然后,您的枚舉器可以迭代此數組,從提供的隨機索引返回源列表中的元素。
這應該這樣做:
public static IEnumerable<T> YieldRandom<T>(this IList<T> items) {
Random random = new Random();
HashSet<int> yielded = new HashSet<int>(items.Count);
for (int i=0; i<items.Count; i++) {
// find an index we haven't yielded yet
int yieldIndex;
do {
yieldIndex = random.Next(items.Count);
}
while (yielded.Contains(yieldIndex));
yielded.Add(yieldIndex);
yield return items[yieldIndex];
}
}
我相信更多的LINQ可以在地方使用:)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.