《C#并行编程高级教程》第2章 命令式编程 笔记

Parallel.Invoke

并行执行多个方法,只有在所有方法都执行后才会返回
static void Main(string[] args)
{
    Parallel.Invoke(
    () => ConvertEllipses(),
    () => ConvertRectangles(),
    () => ConvertLines(),
    () => ConvertText());
    System.Console.ReadLine();
}
 
static void ConvertEllipses()
{
    System.Console.WriteLine("Ellipses converted.");
}
 
 
static void ConvertRectangles()
{
    System.Console.WriteLine("Rectangles converted.");
}
 
static void ConvertLines()
{
    System.Console.WriteLine("Lines converted.");
}
 
static void ConvertText()
{
    System.Console.WriteLine("Text converted.");
}
 
先给两段基本代码,方便后面理解。
将Byte[]转成16进制表示的字符串
private static string ConvertToHexString(Byte[] byteArray)
{
    // Convert the byte array to hexadecimal string
    var sb = new StringBuilder(byteArray.Length);
    for (int i = 0; i < byteArray.Length; i++)
    {
        sb.Append(byteArray[i].ToString("X2"));
    }
    return sb.ToString();
}
生成一些AES的Key,并计时
AesManaged在System.Security.Cryptography
Stopwatch和Debug在System.Diagnostics
 
private const int NUM_MD5_HASHES = 100000;
private static void GenerateAESKeys()
{
    var sw = Stopwatch.StartNew();
    var aesM = new AesManaged();
    for (int i = 1; i <= NUM_AES_KEYS; i++)
    {
        aesM.GenerateKey();
        byte[] result = aesM.Key;
        string hexString = ConvertToHexString(result);
        // Console.WriteLine("AES KEY: {0} ", hexString);
    }
    Debug.WriteLine("AES: " + sw.Elapsed.ToString());
}
 

Parallel.For

不支持浮点数和进步。无法保证迭代执行的顺序
private static void ParallelGenerateAESKeys()
{
    var sw = Stopwatch.StartNew();
    Parallel.For(1, NUM_AES_KEYS + 1, (int i) =>
    {
        var aesM = new AesManaged();
        byte[] result = aesM.Key;
        string hexString = ConvertToHexString(result);
        // Console.WriteLine(“AES KEY: {0} “, hexString);
    });
    Debug.WriteLine("AES: " + sw.Elapsed.ToString());
}

Parallel.ForEach

利用一个范围整数作为一组数据,通过一个分区器,把数据分成一组数据块。每一块的数据都通过循环的方式处理,而这些循环都是并行的。
private static void ParallelPartitionGenerateAESKeys()
{
    var sw = Stopwatch.StartNew();
    Parallel.ForEach(Partitioner.Create(1, NUM_AES_KEYS + 1), range =>
    {
        var aesM = new AesManaged();
        Debug.WriteLine(
            "AES Range ({0}, {1}. TimeOfDay before inner loop starts: {2})",
            range.Item1, range.Item2,
            DateTime.Now.TimeOfDay);
        for (int i = range.Item1; i < range.Item2; i++)
        {
            aesM.GenerateKey();
            byte[] result = aesM.Key;
            string hexString = ConvertToHexString(result);
            // Console.WriteLine(“AES KEY: {0} “, hexString);
        }
    });
    Debug.WriteLine("AES: " + sw.Elapsed.ToString());
}

根据内核数目优化分区

Parallel.ForEach(
    Partitioner.Create(1,NUM_AES_KEYS,((int)(NUM_AES_KEYS / Environment.ProcessorCount) + 1)),
    range =>
    {
        //...
    });

使用IEnumerable数据源

private const int NUM_MD5_HASHES = 100000;
private static IEnumerable<int> GenerateMD5InputData()
{
    return Enumerable.Range(1, NUM_MD5_HASHES);
}
 
private static void ParallelForEachGenerateMD5Hashes()
{
    var sw = Stopwatch.StartNew();
    var inputData = GenerateMD5InputData();
    Parallel.ForEach(inputData, (int number) =>
    {
        var md5M = MD5.Create();
        byte[] data =
            Encoding.Unicode.GetBytes(
                Environment.UserName + number.ToString());
        byte[] result = md5M.ComputeHash(data);
        string hexString = ConvertToHexString(result);
        // Console.WriteLine("MD5 HASH: {0}", hexString);
    });
    Debug.WriteLine("MD5: " + sw.Elapsed.ToString());
}

从并行循环中退出

在参数中使用ParallelLoopState,就可以使用loopState.Break();或者loopState.Stop();进行退出。其中的差别在于,假设调用Break的时候正在处理迭代100,那么可以保证小于100的迭代都被执行,而Stop不保证这个。
ParallelLoopResult作为返回值,可以知道是否是正常完成或者被Break的
ParallelLoopResult loopResult = Parallel.ForEach(inputData,
(int number, ParallelLoopState loopState) =>
{
    //...
    loopState.Break();
    return;
    //...
});

捕获并行循环的异常

try
{
    loopResult = Parallel.ForEach(inputData,
    (int number, ParallelLoopState loopState) =>
    {
        //...
        throw new Exception();
        //..
    });
}
catch (AggregateException ex)
{
    foreach (Exception innerEx in ex.InnerExceptions)
    {
        Debug.WriteLine(innerEx.ToString());
    }
}

ParaleelOption

用于修改并行度。
private static void ParallelGenerateAESKeysMaxDegree(int maxDegree)
{
    var parallelOptions = new ParallelOptions();
    parallelOptions.MaxDegreeOfParallelism = maxDegree;
    var sw = Stopwatch.StartNew();
    Parallel.For(1, NUM_AES_KEYS + 1, parallelOptions, (int i) =>
    {
        var aesM = new AesManaged();
        byte[] result = aesM.Key;
        string hexString = ConvertToHexString(result);
        // Console.WriteLine(“AES KEY: {0} “, hexString);
    });
    Debug.WriteLine("AES: " + sw.Elapsed.ToString());
}
 
 





posted @ 2013-08-03 10:24  atskyline  阅读(2105)  评论(0编辑  收藏  举报