C#异步编程之数据并行及任务并行

news2024/11/18 20:28:13

基于Parallel.ForEach的数据并行使用

1.数据非并行

var items = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
DateTime t1 = DateTime.Now;
foreach (var item in items)
{
    Console.WriteLine("数据非并行输出:{0}", item);
}

2.数据并行,只要使用Parallel.ForEach

Parallel.ForEach(items, item => Console.WriteLine("数据并行输出:{0}", item));

3.非并行与并行耗时对比

var items = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
DateTime t1 = DateTime.Now;
foreach (var item in items)
{
    Console.WriteLine("数据非并行输出:{0}", item);
}
DateTime t2 = DateTime.Now;
TimeSpan t3 = t2 - t1;
Console.WriteLine("非数据并行输出耗费时间:毫秒:{0},微秒:{1}", t3.Milliseconds, t3.Microseconds);

t1 = DateTime.Now;
Parallel.ForEach(items, item => Console.WriteLine("数据并行输出:{0}", item));
t2 = DateTime.Now;
t3 = t2 - t1;
Console.WriteLine("数据并行输出耗费时间:毫秒:{0},微秒:{1}", t3.Milliseconds, t3.Microseconds);

 基于Parallel.For的数据并行使用

1. Parallel.For返回一个ParallelLoopResult结构

public struct ParallelLoopResult
{
	internal bool _completed;

	internal long? _lowestBreakIteration;

	public bool IsCompleted => _completed;

	public long? LowestBreakIteration => _lowestBreakIteration;
}

下面的result类型为 ParallelLoopResult结构

var result = Parallel.For(1, 101, (i, state) => {
});

 完整示例:

//Parallel.For返回一个ParallelLoopResult结构
var result = Parallel.For(1, 101, (i, state) => {
    
    int delay;
    lock (rnd);
    delay = rnd.Next(1, 1001);//随机生成1到1001之间随机数
    Thread.Sleep(delay);//随机休眠线程

    //循环调用了退出方法Break
    if (state.ShouldExitCurrentIteration)
    {
        if (state.LowestBreakIteration < i)
        {
            Console.WriteLine("循环调用了退出方法Break()");
            return;
        }
    }

    if (i == breakIndex)
    {
        Console.WriteLine($"随机数与索引相同,将退出循环,索引: {i}");
        state.Break();//退出循环
    }

    Console.WriteLine($"完成循环遍历,当前循环索引: {i}");

});

if (result.LowestBreakIteration.HasValue)
    Console.WriteLine($"\nLowest Break Iteration: {result.LowestBreakIteration}");
else
    Console.WriteLine($"\nNo lowest break iteration.");

基于Parallel.ForEach的数据并行操作数据并使用局部变量

//初始化数组
int[] input = { 4, 1, 6, 2, 9, 5, 10, 3 };
int sum = 0;

try
{
    Parallel.ForEach(
            input,                          //要并行遍历的集合
            () => 0,                        //线程本地初始化
            //n当前遍历元素,loopState:并行状态对象,localSum局部变量
            (n, loopState, localSum) =>     //匿名函数,localSum会初始化为0
            {
                localSum += n;//累加元素
                //输出当前线程ID,元素值,与累加后的元素值
                Console.WriteLine("Thread={0}, n={1}, localSum={2}", Thread.CurrentThread.ManagedThreadId, n, localSum);
                //返回累加后的值
                return localSum;
            },
            //任务动作,传入线程本地变量localSum
            (localSum) => Interlocked.Add(ref sum, localSum) //多线程元子性操作共享变量
    );
    //输出并行操作后的结果
    Console.WriteLine("\nSum={0}", sum);
}
catch (AggregateException e) //捕获线程操作异常
{
    Console.WriteLine("并行操作数据异常\n{0}", e.Message.ToString());
}

基于Parallel.Invoke的任务并行操作

//静态函数实现,供并行任务使用
static void BasicAction()
{
    Console.WriteLine("静态方法BasicAction, Thread={0}", Thread.CurrentThread.ManagedThreadId);
}
try
{
    Parallel.Invoke(
        BasicAction,    // 任务1 - 静态方法
        () =>           // 任务2 - lambda表达式
        {
            Console.WriteLine($"lambda表达式, Thread:{Thread.CurrentThread.ManagedThreadId}");
        },
        delegate ()     // 任务3 - 肉联委托
        {
            Console.WriteLine($"肉联委托, Thread:{Thread.CurrentThread.ManagedThreadId}");
        }
    );
}
catch (AggregateException e) //捕获任务并行异常
{
    Console.WriteLine($"抛出异常:{e.InnerException.ToString()}");
}

基于Parallel.ForEachAsync的异常并行操作,异步方法要添加await关键字

await Parallel.ForEachAsync(Enumerable.Range(1, 100),
    async (_, _) => {
        await Task.Delay(1000);
    });

在任务中使用数据并行:

//创建任务线程
Task _t = new Task(() => {
    Console.WriteLine($"这个是任务子线程");
    Parallel.ForEach(items, (item, state) =>{
        Console.WriteLine($"{item},{state}");
    });
});
Console.WriteLine($"任务线程:{_t.Id}");
_t.Start();//开始任务

任务的运行及等待

Thread.CurrentThread.Name = "主线程";
//创建任务并运行
Task taskA = Task.Run(
    () => {
        Thread.CurrentThread.Name = "任务子线程";
        Console.WriteLine($"当前线程名:-> '{Thread.CurrentThread.Name}',线程ID:{Thread.CurrentThread.ManagedThreadId}");
        Console.WriteLine("这个是在任务中输出的信息"); //使用匿名函数
    }
    );
Console.WriteLine($"当前线程名: '{Thread.CurrentThread.Name}',线程ID:{Thread.CurrentThread.ManagedThreadId}");
taskA.Wait();//等待任务完成

任务分离:

//分离任务
var outer = Task.Factory.StartNew(() =>
{
    Console.WriteLine("任务开始...");

    var child = Task.Factory.StartNew(() =>
    {
        Thread.SpinWait(5000000);
        Console.WriteLine("任务分离成功.");
    });
});
outer.Wait();
Console.WriteLine("任务结束.");

任务阻塞:

//阻塞任务
Task[] tasks = new Task[3]
{
    Task.Factory.StartNew(() => Console.WriteLine("任务1.")),
    Task.Factory.StartNew(() => Console.WriteLine("任务2.")),
    Task.Factory.StartNew(() => Console.WriteLine("任务3."))
};
Task.WaitAll(tasks);//阻塞直接所有任务完成

多任务使用:

//多任务使用
Task[] taskArray = new Task[10];
for (int i = 0; i < taskArray.Length; i++)
{
    //使用任务工厂启动任务
    taskArray[i] = Task.Factory.StartNew((Object obj) =>
    {
        CustomData data = obj as CustomData;//实例化类对象
        if (data == null) return;

        data.ThreadNum = Thread.CurrentThread.ManagedThreadId;//赋值当前线程ID
    },
    new CustomData() { Name = i, CreationTime = DateTime.Now.Ticks });
};
Task.WaitAll(taskArray);
//遍历任务
foreach (var task in taskArray)
{
    var data = task.AsyncState as CustomData;
    if (data != null)
        Console.WriteLine("任务 #{0} 已创建于 {1}, 在线程 #{2}.",
                          data.Name, data.CreationTime, data.ThreadNum);
}

class CustomData
{
    public long CreationTime;
    public int Name;
    public int ThreadNum;
}

完整Demo:

// See https://aka.ms/new-console-template for more information

using System;
using System.Diagnostics;

var items = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
DateTime t1 = DateTime.Now;
foreach (var item in items)
{
    Console.WriteLine("数据非并行输出:{0}", item);
}
DateTime t2 = DateTime.Now;
TimeSpan t3 = t2 - t1;
Console.WriteLine("非数据并行输出耗费时间:毫秒:{0},微秒:{1}", t3.Milliseconds, t3.Microseconds);

t1 = DateTime.Now;
Parallel.ForEach(items, item => Console.WriteLine("数据并行输出:{0}", item));
t2 = DateTime.Now;
t3 = t2 - t1;
Console.WriteLine("数据并行输出耗费时间:毫秒:{0},微秒:{1}", t3.Milliseconds, t3.Microseconds);


var rnd = new Random();
Console.WriteLine("开始遍历...");
int breakIndex = rnd.Next(1, 11);
Console.WriteLine($"Will call Break at iteration {breakIndex}\n");

//Parallel.For返回一个ParallelLoopResult结构
var result = Parallel.For(1, 101, (i, state) => {
    
    int delay;
    lock (rnd);
    delay = rnd.Next(1, 1001);//随机生成1到1001之间随机数
    Thread.Sleep(delay);//随机休眠线程

    //循环调用了退出方法Break
    if (state.ShouldExitCurrentIteration)
    {
        if (state.LowestBreakIteration < i)
        {
            Console.WriteLine("循环调用了退出方法Break()");
            return;
        }
    }

    if (i == breakIndex)
    {
        Console.WriteLine($"随机数与索引相同,将退出循环,索引: {i}");
        state.Break();//退出循环
    }

    Console.WriteLine($"完成循环遍历,当前循环索引: {i}");

});

if (result.LowestBreakIteration.HasValue)
    Console.WriteLine($"\nLowest Break Iteration: {result.LowestBreakIteration}");
else
    Console.WriteLine($"\nNo lowest break iteration.");

//初始化数组
int[] input = { 4, 1, 6, 2, 9, 5, 10, 3 };
int sum = 0;

try
{
    Parallel.ForEach(
            input,                          //要并行遍历的集合
            () => 0,                        //线程本地初始化
            //n当前遍历元素,loopState:并行状态对象,localSum局部变量
            (n, loopState, localSum) =>     //匿名函数,localSum会初始化为0
            {
                localSum += n;//累加元素
                //输出当前线程ID,元素值,与累加后的元素值
                Console.WriteLine("Thread={0}, n={1}, localSum={2}", Thread.CurrentThread.ManagedThreadId, n, localSum);
                //返回累加后的值
                return localSum;
            },
            //任务动作,传入线程本地变量localSum
            (localSum) => Interlocked.Add(ref sum, localSum) //多线程元子性操作共享变量
    );
    //输出并行操作后的结果
    Console.WriteLine("\nSum={0}", sum);
}
catch (AggregateException e) //捕获线程操作异常
{
    Console.WriteLine("并行操作数据异常\n{0}", e.Message.ToString());
}


//静态函数实现,供并行任务使用
static void BasicAction()
{
    Console.WriteLine("静态方法BasicAction, Thread={0}", Thread.CurrentThread.ManagedThreadId);
}
try
{
    Parallel.Invoke(
        BasicAction,    // 任务1 - 静态方法
        () =>           // 任务2 - lambda表达式
        {
            Console.WriteLine($"lambda表达式, Thread:{Thread.CurrentThread.ManagedThreadId}");
        },
        delegate ()     // 任务3 - 肉联委托
        {
            Console.WriteLine($"肉联委托, Thread:{Thread.CurrentThread.ManagedThreadId}");
        }
    );
}
catch (AggregateException e) //捕获任务并行异常
{
    Console.WriteLine($"抛出异常:{e.InnerException.ToString()}");
}



var watch = Stopwatch.StartNew();
Console.WriteLine(watch.ElapsedMilliseconds);
Console.WriteLine($"当前机器的CPU数量:{Environment.ProcessorCount}");
watch.Restart();

//使用异步并行方法
await Parallel.ForEachAsync(Enumerable.Range(1, 100),
    async (_, _) => {
        await Task.Delay(1000);
    });
watch.Stop();
Console.WriteLine($"花费时间:{watch.ElapsedMilliseconds}");
watch.Restart();

Thread.CurrentThread.Name = "主线程";
//创建任务线程
Task _t = new Task(() => {
    Console.WriteLine($"这个是任务子线程");
    Parallel.ForEach(items, (item, state) =>{
        Console.WriteLine($"{item},{state}");
    });
});
Console.WriteLine($"任务线程:{_t.Id}");
_t.Start();//开始任务

Thread.CurrentThread.Name = "主线程";
//创建任务并运行
Task taskA = Task.Run(
    () => {
        Thread.CurrentThread.Name = "任务子线程";
        Console.WriteLine($"当前线程名:-> '{Thread.CurrentThread.Name}',线程ID:{Thread.CurrentThread.ManagedThreadId}");
        Console.WriteLine("这个是在任务中输出的信息"); //使用匿名函数
    }
    );
Console.WriteLine($"当前线程名: '{Thread.CurrentThread.Name}',线程ID:{Thread.CurrentThread.ManagedThreadId}");
taskA.Wait();//等待任务完成

//分离任务
var outer = Task.Factory.StartNew(() =>
{
    Console.WriteLine("任务开始...");

    var child = Task.Factory.StartNew(() =>
    {
        Thread.SpinWait(5000000);
        Console.WriteLine("任务分离成功.");
    });
});
outer.Wait();
Console.WriteLine("任务结束.");

//阻塞任务
Task[] tasks = new Task[3]
{
    Task.Factory.StartNew(() => Console.WriteLine("任务1.")),
    Task.Factory.StartNew(() => Console.WriteLine("任务2.")),
    Task.Factory.StartNew(() => Console.WriteLine("任务3."))
};
Task.WaitAll(tasks);//阻塞直接所有任务完成

//多任务使用
Task[] taskArray = new Task[10];
for (int i = 0; i < taskArray.Length; i++)
{
    //使用任务工厂启动任务
    taskArray[i] = Task.Factory.StartNew((Object obj) =>
    {
        CustomData data = obj as CustomData;//实例化类对象
        if (data == null) return;

        data.ThreadNum = Thread.CurrentThread.ManagedThreadId;//赋值当前线程ID
    },
    new CustomData() { Name = i, CreationTime = DateTime.Now.Ticks });
};
Task.WaitAll(taskArray);
//遍历任务
foreach (var task in taskArray)
{
    var data = task.AsyncState as CustomData;
    if (data != null)
        Console.WriteLine("任务 #{0} 已创建于 {1}, 在线程 #{2}.",
                          data.Name, data.CreationTime, data.ThreadNum);
}

class CustomData
{
    public long CreationTime;
    public int Name;
    public int ThreadNum;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/537547.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity UI -- (2) 给场景加一个标题

添加Text并将其放到正中位置 我们来增加项目的第一个UI元素&#xff1a;标题。 1. 在Hierarchy中&#xff0c;点击右键&#xff0c;选择UI > Text - TextMeshPro。如果弹出了一个TextMeshPro Importer窗口&#xff0c;选择Import TMP Essentials。TextMeshPro&#xff08;TM…

优雅地处理参数传递:Spring Boot中的技巧

目录 一&#xff1a;四种传参方式 1.1&#xff1a;在 URL 中传递参数 1.2&#xff1a;PathVariable 传递参数&#xff08;Restful 风格&#xff09; 1.3&#xff1a;在请求体中传递参数 1.4&#xff1a;在请求头中传递参数 二&#xff1a;文件上传接口测试 2.1 : test.jav…

5_推荐系统算法详解

推荐系统算法详解 主要内容常用推荐算法分类&#xff08;重点&#xff09;基于人口统计学的推荐算法用户画像 基于内容的推荐算法相似度计算 基于内容推荐系统的高层次结构特征工程数值型特征处理 类别型特征处理时间型特征处理统计型特征处理推荐系统常见反馈数据基于 UGC 的推…

【c语言】组件化打包—动态链接库dll

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c语言系列专栏&#xff1a;c语言之路重点知识整合 &#x…

Qt创建多线程的两种方法

Qt创建多线程的两种方法 [1] Qt创建多线程的两种方法1.摘要2.Qt多线程方法1 继承QThread2.1写一个继承于QThread的线程2.2 QThread的几个函数quit、exit、terminate函数2.3 正确的终止一个线程2.4 如何正确启动一个线程2.5 继承QThread的一些总结 Qt使用多线程的一些心得——2.…

什么是边缘计算盒子?边缘计算盒子可以做什么?一文带你了解边缘计算云服务器 ECS

上文&#xff0c;我们已经为大家介绍了什么是边缘计算、边缘计算的诞生、以及边缘计算与CDN之间的关系&#xff0c;感兴趣的小伙伴欢迎阅读以往文章&#xff1a; 边缘计算节点是啥&#xff1f;边缘计算与CDN有什么关系&#xff1f;一文带你了解边缘计算节点BEC&#xff08;1&am…

在线PS软件有哪些不错的推荐

许多新的UI设计合作伙伴非常关心在线ps工具的选择。现在市场上有各种各样的ps网页替代工具&#xff0c;数量众多&#xff0c;令人眼花缭乱。本文简要介绍了10个在线PS工具&#xff0c;我相信一定有一个适合你&#xff01; 1.即时设计 即时设计是一款在线 UI 设计工具&#xf…

渗透测试--5.1.Crunch创建密码字典

目录 1.crunch简介 2.常用命令 3.使用实例 &#xff08;1&#xff09;.生成字母组合 &#xff08;2&#xff09;. 生成缺位的手机号码 &#xff08;3&#xff09;.生成pass01-pass99所有组合 &#xff08;4&#xff09;.生成六位密码&#xff0c;其中前四位为pass&#xf…

docker-compose部署开发环境

docker-compose部署开发环境 部署nginx欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义…

Java内部类与匿名类

内部类 定义&#xff1a; 一个类的内部又完整的嵌套了另一个类结构&#xff0c;被嵌套的类就被我们称为内部类&#xff0c;嵌套内部类的类被我们称为外部类 //外部类 class Outer {//内部类class Inner{} }package Innerclass;//外部其他类 public class c1 { }class Outer {/…

数据结构--线段树--洛谷模板线段树1-2

写在前面&#xff1a; 学习之前需要知道以下内容&#xff1a; 1. 递归 2. 二叉树 文章目录 线段树介绍用途建树修改单点修改区间修改 查询 代码实现。建树更新lazy传递查询优化一下 练习洛谷 P3372 【模板】线段树 1题目描述题解 【模板】线段树 2题目描述题解 线段树 介绍 …

生产流程图怎么制作?思路提供

生产流程图是一种图表&#xff0c;用来展示生产流程中的各个环节及其顺序。这种图表可以帮助企业管理者更好地了解生产过程中的各个环节&#xff0c;从而更好地进行管理和优化。生产流程图通常包括各个生产环节的名称、所需时间、参与人员、设备和工具等信息。 在制作生产流程图…

虚拟机 03 补充 redis的命令

Redis的操作命令&#xff1a; Redis的启动命令&#xff1a;redis-server redis.conf 进入redis的客户端操作命令&#xff1a;redis-cli -p 6379 退出redis客户端的操作命令&#xff1a;exit或者ctrlc 关闭redis的命令&#xff1a;redis-cli -p 6379 shutdown Redis数据操作命令…

免费优质的网页设计素材网站推荐

找到一个免费优质的网页设计素材网站并不容易。 有些网站要么需要网站的会员&#xff0c;要么设计素材质量差。本文整理总结了10个免费的网页设计材料网站&#xff0c;希望给大家带来一些帮助。 即时设计资源社区 即时设计资源社区是由在线协同设计软件即时设计推出的设计社…

2023乡村振兴三点:粮食安全,数字乡村,特色产业

2023乡村振兴三条&#xff1a;粮食安全&#xff0c;数字乡村&#xff0c;特色产业 人工智能总趋势在减少就业 乡村生活综合服务领域&#xff5e; 可能是以后吸纳劳动力的重要领域 农业现代化最后在实现中… 趣讲大白话&#xff1a;人没事干&#xff0c;咋办 【趣讲信息科技168期…

基于 debian 发行版本的密码设置策略

密码过期时间设置 修改 /etc/login.defs 中的选项 PASS_MAX_DAYS 99999 代表不过期 我们将该值改为 90 密码复杂度设置 需要安装 pam 扩展包 libpam-pwquality 或 libpam-cracklib 。 这里选择安装 libpam-cracklib sudo apt updatesudo apt install libpam-cracklib查看…

虚拟机 03 redis安装和启动服务

redis在linux上的安装&#xff1a; 01.先找到redis的压缩文件 这里的是gz格式的。 02.在linux系统中&#xff0c;先去切换到根目录先 使用命令 cd / 再切换到usr/local/src中 直接把压缩文件拖入到linux系统的命令行中 src文件中会出现redis-5.0.4.tar.gz的文件 03.对这个文…

arm作业

用for循环实现1~100之间的和13BA for(i1;i<100;i) { sum sumi; }

面试7轮,结果对接的HR离职了……

面试鹅厂总共进行了7轮&#xff0c;还没有结果。先是面了三轮&#xff0c;然后hr告诉她没hc了&#xff0c;然后又推荐了另外一个岗位&#xff0c;又面了四轮。然后追问HR后续的进展&#xff0c;她告诉我已经离职了&#xff0c;让我联系另外一个同事。 这么说吧&#xff0c;大厂…

密码学A5算法VHDL设计及仿真验证

A5算法是一种用于GSM(Global System for Mobile Communications)移动通信标准的加密算法。它是一种对称密钥算法,使用一个64位密钥和一个22位帧号作为输入,生成一个228位的伪随机序列,该序列被用于加密语音和数据通信。 A5算法由三个线性反馈移位寄存器(LFSR)组成,每个…