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

基于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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Docker高频使用命令总结(镜像与容器命令)

目录 一.Docker常用命令总结 1.镜像命令管理 2.容器命令管理 二.Docker镜像操作命令 1.docker search&#xff1a;搜索镜像 2.docker pull&#xff1a;下载镜像 3.docker push&#xff1a;上传镜像 4.docker images&#xff1a;查看本地镜像 5.docker inspect &#x…

360+ChatGLM联手研发中国版“微软+OpenAI”

文章目录 前言360与智谱AI强强联合什么是智谱AI360智脑360GLM与360GPT大模型战略布局写在最后 前言 5月16日&#xff0c;三六零集团&#xff08;下称“360”&#xff09;与智谱AI宣布达成战略合作&#xff0c;双方共同研发的千亿级大模型“360GLM”已具备新一代认知智能通用模…

Springboot——事物管理

文章目录 事务管理一、 Spring事务管理1.1 事务回顾1.2 案例&#xff1a; 解散部门&#xff08;未开启事务&#xff09;1.3 事务管理注解Transactional1.4 事务管理日志开关1.5 rollbackFor 异常回滚属性1.6 propagation 事务传播行为1.7 解散部门并记录操作日志1.7.1 创建数据…

技术探秘:揭秘Bean Factory与FactoryBean的区别!

大家好&#xff0c;我是小米&#xff0c;一个热衷于技术分享的29岁小编。今天&#xff0c;我们来聊一聊在Spring框架中常用的两个概念&#xff1a;beanFactory和FactoryBean。它们虽然看似相似&#xff0c;但实际上有着不同的用途和作用。让我们一起来揭开它们的神秘面纱吧&…

离散数学_九章:关系(6)

&#x1fa90;9.6 偏序 1、⛺偏序关系和偏序集⛲偏序关系⛲偏序&#xff08;关系&#xff09;的例子 a. “大于或等于” 关系b. “整除” 关系c. “包含” 关系 &#x1f3ac;偏序集&#x1f3ac;可比性&#xff08;comparability&#xff09; " ≼ " 符号a. 可比 &a…

基于野火F407骄阳开发板的苹果采摘机器人机械臂的采摘轨迹与夹持器的采摘动作的设计(1)

基于野火F407骄阳开发板的苹果采摘机器人机械臂的采摘轨迹与夹持器的采摘动作的设计&#xff08;1&#xff09; 苹果采摘机器人1、采摘流程与硬件设计2、机械臂驱动以及采摘轨迹设计2.1、台达A2电机驱动实现2.2、机械臂寻找苹果巡逻轨迹 苹果采摘机器人 1、采摘流程与硬件设计…

C++/Qt 小知识记录3

工作中遇到的一些小问题&#xff0c;总结的小知识记录&#xff1a;C/Qt 小知识 QLineEdit限制输入大于0的正整数QLayout内清空已布局的WidgetWindows结束进程直接结束&#xff0c;子进程不响应结束事件正常结束&#xff0c;子进程响应结束事件 CMake关闭控制台Console实体与值对…

尾调用优化

尾调用优化 最近遇到一个堆栈溢出的问题&#xff0c;分析后发现可收敛为递归边界问题。结合“红宝书”中相关内容和ES6规范中的一些优化机制&#xff0c;整理记录如下。 前言 程序运行时&#xff0c;计算机会为应用程序分配一定的内存空间。应用程序会自行分配所获得的内存空…

数组或结构体赋值时memcpy与直接赋值的效率比较

先上结论&#xff1a; 二者不一定谁快通常情况下&#xff0c;数组维度越大&#xff0c;使用memcpy效率更高数组维度越大&#xff0c;直接赋值耗时主体是循环耗时 Note&#xff1a; “等号赋值”被编译器翻译成一连串的MOV指令&#xff0c;而memcpy则是一个循环。“等号赋值”比…

深入解析PyTorch中的模型定义:原理、代码示例及应用

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

【一起啃书】《机器学习》第六章 支持向量机

文章目录 第六章 支持向量机6.1 间隔和支持向量6.2 对偶问题6.3 核函数6.4 软间隔与正则化6.5 支持向量回归6.6 核方法6.7 一些问题 第六章 支持向量机 6.1 间隔和支持向量 给定训练样本集 D { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x m , y m ) } , y i ∈ { − 1 , …

Day 1 认识软件测试——(软件测试定义、目的、原则)

Day 1 认识软件测试——(软件测试定义、目的、原则) 文章目录 Day 1 认识软件测试——(软件测试定义、目的、原则)软件测试的定义软件测试的目的软件测试的经济学问题黑盒测试白盒测试软件测试原则小结所谓软件测试,就是一个过程或一系列过程,用来确定计算机代码完成了其…

《我命由我不由天》蔡志忠——笔记一

目录 简介 经典摘录 三岁决定一生 父母该什么时候放手 确定将来要成为什么 积极主动为目标而努力 叛逆是最伟大的创意 父亲给蔡志忠最大的影响是教会他两件事 价值观缺陷导致的后果 人有三个阶段 简介 作者 蔡志忠&#xff0c;李虹。 蔡志忠&#xff1a;漫画家、哲…

Vue加SpringBoot实现项目前后端分离

首先需要搭建一个Vue的脚手架项目&#xff08;已经放在gitee里面了&#xff0c;下面是gitee网址&#xff0c;可以直接拉&#xff09; (vue-web: 这个是Vue项目模板&#xff0c;没有后台数据) 那么接下来就是实现前后端分离的步骤 首先我们需要有一个登录页面 登录的点击事件利用…

图神经网络:(节点分类)在KarateClub数据集上动手实现图神经网络

文章说明&#xff1a; 1)参考资料&#xff1a;PYG官方文档。超链。 2)博主水平不高&#xff0c;如有错误还望批评指正。 3)我在百度网盘上传了这篇文章的jupyter notebook。超链。提取码8888。 文章目录 文献阅读&#xff1a;代码实操&#xff1a; 文献阅读&#xff1a; 参考文…

【Hello Algorithm】归并排序及其面试题

作者&#xff1a;小萌新 专栏&#xff1a;算法 作者简介&#xff1a;大二学生 希望能和大家一起进步 本篇博客简介&#xff1a;介绍归并排序和几道面试题 归并排序及其面试题 归并排序归并排序是什么归并排序的实际运用归并排序的迭代写法归并排序的时间复杂度 归并排序算法题小…

(十一)地理数据库创建——创建新的地理数据库

地理数据库创建——创建新的地理数据库 目录 地理数据库创建——创建新的地理数据库 1.地理数据库概述2.地理数据库建立一般过程2.1地理数据库设计2.2地理数据库建立2.2.1从头开始建立一个新的地理数据库2.2.2移植已经存在数据到地理数据库2.2.3用CASE工具建立地理数据库 2.3建…

Python 科研绘图可视化(后处理)Matplotlib - 2D彩图

Introduction 科研可视化是将数据和信息转化为可视化形式的过程&#xff0c;旨在通过图形化展示数据和信息&#xff0c;使得科研工作者能够更好地理解和分析数据&#xff0c;并从中发现新的知识和洞见。科研可视化可以应用于各种领域&#xff0c;如生物学、物理学、计算机科学…

C++类和对象再探

文章目录 const成员再谈构造函数成员变量的定义函数体内赋值初始化列表 隐式类型转换explicitstatic成员 const成员 我们知道在调用类的成员函数时,会有一个默认的this指针且这个this指针时不可以被修改的,例如在日期类中,会有隐式的Date * const this;注意这里默认会在this前…

一五一、web+小程序骨架屏整理

骨架屏介绍 请点击查看智能小程序骨架屏 车载小程序骨架屏 车载小程序为方便开发者设置骨架屏&#xff0c;在智能小程序的基础上抽取出骨架屏模板&#xff0c;开发者只需要在 skeleton 文件夹下配置config.json&#xff08;page 和骨架屏的映射关系文件&#xff09;即可生效骨…