在这个问题中注意到:Randomize a List<T>你可以在列表上实现一个shuffle方法;像其中一个答案提到:
using System.Security.Cryptography;
...
public static void Shuffle<T>(this IList<T> list)
{
RNGCryptoServiceProvider provider = new RNGCryptoServiceProvider();
int n = list.Count;
while (n > 1)
{
byte[] box = new byte[1];
do provider.GetBytes(box);
while (!(box[0] < n * (Byte.MaxValue / n)));
int k = (box[0] % n);
n--;
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
有人知道是否可以使用C#4中的一些新功能“并行”这个?
只是好奇心。
全心全意,
-R
答案 0 :(得分:1)
任何就地shuffle都不太适合并行化。特别是因为随机播放需要一个随机分量(超出范围),所以无法定位部分问题。
答案 1 :(得分:1)
好吧,你可以很容易地并行化生成随机数的代码 - 当使用加密安全随机数生成器时,可能成为瓶颈。然后,您可以在执行交换的单个线程中使用该序列的随机数(需要保留其顺序)。
我刚刚遇到的一个问题是,RNGCryptoServiceProvider
不是线程安全的(System.Random
也不是)。你需要尽可能多的随机数生成器作为线程来完成这项工作。基本上它变得有点难看:(
答案 2 :(得分:1)
您的问题不明确,但您可以使用并行框架来帮助并行执行某些操作,但这取决于您是否要获取字节,然后将它们随机播放,因此获取字节是并行的,或者,如果你想一次洗牌多个名单。
如果是前者,我建议您首先将代码分解为更小的函数,这样您就可以进行一些分析,看看瓶颈在哪里,如果获取字节是瓶颈,那么就这样做吧并行可能会有所作为。通过测试,您可以测试新功能并确定是否值得增加复杂性。
static RNGCryptoServiceProvider provider = new RNGCryptoServiceProvider();
private static byte[] GetBytes() {
byte[] box = new byte[1];
do provider.GetBytes(box);
while (!(box[0] < n * (Byte.MaxValue / n)));
return box;
}
private static IList<T> InnerLoop(int n, IList<T> list) {
var box = GetBytes(n);
int k = (box[0] % n);
T value = list[k];
list[k] = list[n];
list[n] = value;
return list;
}
public static void Shuffle<T>(this IList<T> list)
{
int n = list.Count;
while (n > 1)
{
list = InnerLoop(n, list);
n--;
}
}
关于如何拆分函数,这是一个粗略的想法,因此您可以替换GetBytes
函数,但您可能需要进行一些其他更改来测试它。
获取一些数字对于确保获得足够的利益以保证增加复杂性至关重要。
您可能希望将处理InnerLoop
的{{1}}中的行移动到一个单独的函数中,这样您就可以看到它是否很慢并且可能会换出一些算法来改进它,但是,你需要知道你需要多快的整个洗牌操作。
但是如果你想做多个列表那么这很容易,你可能想看看list
。
<强>更新强>
上面的代码只是为了展示如何将其分解为更小的功能,不是一个有效的解决方案。如果有必要将我放入静态变量的Provider类移动到一个函数中,然后将其作为参数传递,那么可能需要完成。我没有测试代码,但我的建议是基于获取分析然后看看如何提高它的性能,特别是因为我不确定它是什么意思并行完成。可能有必要按顺序构建一个数组,然后将它们混合,然后首先看看每个操作所需的时间,然后看看是否需要并行执行。
如果使用多个线程,可能还需要使用并发数据结构,以便不必通过必须自己同步来支付罚金,但是,根据瓶颈的位置,可能不再需要这样做。
<强>更新强>
根据我的评论的答案,您可能希望查看并行库中的各种功能,但此页面可能会有所帮助。 http://msdn.microsoft.com/en-us/library/dd537609.aspx
您可以创建函数的PLINQ
版本,并将其作为参数传递。使用此库有多种方法可以并行执行此功能,因为您已经没有任何全局变量,只需丢失Func
运算符。
你会想要在添加更多线程时获取数字,看看你开始看到性能下降的地方,因为你不会看到1:1的改进,所以,如果你添加2个线程就赢了“ t快两倍,所以只需测试并查看哪里有更多线程的问题。由于你的函数是CPU绑定的,你可能希望每个核心只有一个线程,作为一个粗略的起点。