8天玩转并行开发——第五天 同步机制(下)

   

     承接上一篇,我们继续说下.net4.0中的同步机制,是的,当出现了并行计算的时候,轻量级别的同步机制应运而生,在信号量这一块

出现了一系列的轻量级,今天继续介绍下面的3个信号量 CountdownEvent,SemaphoreSlim,ManualResetEventSlim。

 

一:CountdownEvent

     这种采用信号状态的同步基元非常适合在动态的fork,join的场景,它采用“信号计数”的方式,就比如这样,一个麻将桌只能容纳4个

人打麻将,如果后来的人也想搓一把碰碰运气,那么他必须等待直到麻将桌上的人走掉一位。好,这就是简单的信号计数机制,从技术角

度上来说它是定义了最多能够进入关键代码的线程数。

     但是CountdownEvent更牛X之处在于我们可以动态的改变“信号计数”的大小,比如一会儿能够容纳8个线程,一下又4个,一下又10个,

这样做有什么好处呢?还是承接上一篇文章所说的,比如一个任务需要加载1w条数据,那么可能出现这种情况。

 

加载User表:         根据user表的数据量,我们需要开5个task。

加载Product表:    产品表数据相对比较多,计算之后需要开8个task。

加载order表:       由于我的网站订单丰富,计算之后需要开12个task。

 

先前的文章也说了,我们需要协调task在多阶段加载数据的同步问题,那么如何应对这里的5,8,12,幸好,CountdownEvent给我们提供了

可以动态修改的解决方案。

 

  1 using System.Collections.Concurrent;
  2 using System.Threading.Tasks;
  3 using System;
  4 using System.Diagnostics;
  5 using System.Collections.Generic;
  6 using System.Linq;
  7 using System.Threading;
  8 
  9 class Program
 10 {
 11     //默认的容纳大小为“硬件线程“数
 12     static CountdownEvent cde = new CountdownEvent(Environment.ProcessorCount);
 13 
 14     static void Main(string[] args)
 15     {
 16         //加载User表需要5个任务
 17         var userTaskCount = 5;
 18 
 19         //重置信号
 20         cde.Reset(userTaskCount);
 21 
 22         for (int i = 0; i < userTaskCount; i++)
 23         {
 24             Task.Factory.StartNew((obj) =>
 25             {
 26                 LoadUser(obj);
 27             }, i);
 28         }
 29 
 30         //等待所有任务执行完毕
 31         cde.Wait();
 32 
 33         Console.WriteLine("\nUser表数据全部加载完毕!\n");
 34 
 35         //加载product需要8个任务
 36         var productTaskCount = 8;
 37 
 38         //重置信号
 39         cde.Reset(productTaskCount);
 40 
 41         for (int i = 0; i < productTaskCount; i++)
 42         {
 43             Task.Factory.StartNew((obj) =>
 44             {
 45                 LoadProduct(obj);
 46             }, i);
 47         }
 48 
 49         cde.Wait();
 50 
 51         Console.WriteLine("\nProduct表数据全部加载完毕!\n");
 52 
 53         //加载order需要12个任务
 54         var orderTaskCount = 12;
 55 
 56         //重置信号
 57         cde.Reset(orderTaskCount);
 58 
 59         for (int i = 0; i < orderTaskCount; i++)
 60         {
 61             Task.Factory.StartNew((obj) =>
 62             {
 63                 LoadOrder(obj);
 64             }, i);
 65         }
 66 
 67         cde.Wait();
 68 
 69         Console.WriteLine("\nOrder表数据全部加载完毕!\n");
 70 
 71         Console.WriteLine("\n(*^__^*) 嘻嘻,恭喜你,数据全部加载完毕\n");
 72 
 73         Console.Read();
 74     }
 75 
 76     static void LoadUser(object obj)
 77     {
 78         try
 79         {
 80             Console.WriteLine("当前任务:{0}正在加载User部分数据!", obj);
 81         }
 82         finally
 83         {
 84             cde.Signal();
 85         }
 86     }
 87 
 88     static void LoadProduct(object obj)
 89     {
 90         try
 91         {
 92             Console.WriteLine("当前任务:{0}正在加载Product部分数据!", obj);
 93         }
 94         finally
 95         {
 96             cde.Signal();
 97         }
 98     }
 99 
100     static void LoadOrder(object obj)
101     {
102         try
103         {
104             Console.WriteLine("当前任务:{0}正在加载Order部分数据!", obj);
105         }
106         finally
107         {
108             cde.Signal();
109         }
110     }
111 }

 


我们看到有两个主要方法:Wait和Signal。每调用一次Signal相当于麻将桌上走了一个人,直到所有人都搓过麻将wait才给放行,这里同样要

注意也就是“超时“问题的存在性,尤其是在并行计算中,轻量级别给我们提供了”取消标记“的机制,这是在重量级别中不存在的,比如下面的

重载public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken),具体使用可以看前一篇文章的介绍。

 

二:SemaphoreSlim

     在.net 4.0之前,framework中有一个重量级的Semaphore,人家可以跨进程同步,咋轻量级不行,msdn对它的解释为:限制可同时访问

某一资源或资源池的线程数。关于它的重量级demo,我的上一个系列有演示,你也可以理解为CountdownEvent是 SemaphoreSlim的功能加

强版,好了,举一个轻量级使用的例子。

 1 using System.Collections.Concurrent;
 2 using System.Threading.Tasks;
 3 using System;
 4 using System.Diagnostics;
 5 using System.Collections.Generic;
 6 using System.Linq;
 7 using System.Threading;
 8 
 9 class Program
10 {
11     static SemaphoreSlim slim = new SemaphoreSlim(Environment.ProcessorCount, 12);
12 
13     static void Main(string[] args)
14     {
15         for (int i = 0; i < 12; i++)
16         {
17             Task.Factory.StartNew((obj) =>
18             {
19                 Run(obj);
20             }, i);
21         }
22 
23         Console.Read();
24     }
25 
26     static void Run(object obj)
27     {
28         slim.Wait();
29 
30         Console.WriteLine("当前时间:{0}任务 {1}已经进入。", DateTime.Now, obj);
31 
32         //这里busy3s中
33         Thread.Sleep(3000);
34 
35         slim.Release();
36     }
37 }

 


同样,防止死锁的情况,我们需要知道”超时和取消标记“的解决方案,像SemaphoreSlim这种定死的”线程请求范围“,其实是降低了扩展性,

所以说,试水有风险使用需谨慎,在觉得有必要的时候使用它。

 

三: ManualResetEventSlim

     相信它的重量级别大家都知道是ManualReset,而这个轻量级别采用的是"自旋等待“+”内核等待“,也就是说先采用”自旋等待的方式“等待,

直到另一个任务调用set方法来释放它。如果迟迟等不到释放,那么任务就会进入基于内核的等待,所以说如果我们知道等待的时间比较短,采

用轻量级的版本会具有更好的性能,原理大概就这样,下面举个小例子。

 1 using System.Collections.Concurrent;
 2 using System.Threading.Tasks;
 3 using System;
 4 using System.Diagnostics;
 5 using System.Collections.Generic;
 6 using System.Linq;
 7 using System.Threading;
 8 
 9 class Program
10 {
11     //2047:自旋的次数
12     static ManualResetEventSlim mrs = new ManualResetEventSlim(false, 2047);
13 
14     static void Main(string[] args)
15     {
16 
17         for (int i = 0; i < 12; i++)
18         {
19             Task.Factory.StartNew((obj) =>
20             {
21                 Run(obj);
22             }, i);
23         }
24 
25         Console.WriteLine("当前时间:{0}我是主线程{1},你们这些任务都等2s执行吧:\n",
26         DateTime.Now,
27         Thread.CurrentThread.ManagedThreadId);
28         Thread.Sleep(2000);
29 
30         mrs.Set();
31 
32         Console.Read();
33     }
34 
35     static void Run(object obj)
36     {
37         mrs.Wait();
38 
39         Console.WriteLine("当前时间:{0}任务 {1}已经进入。", DateTime.Now, obj);
40     }
41 }

 

 

转载于:https://www.cnblogs.com/huangxincheng/archive/2012/04/08/2437701.html

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

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

相关文章

hive中not in优化

比如&#xff1a;A,B两表&#xff0c;找到ID字段中&#xff0c;存在A表&#xff0c;但不存在B表的数据。A表共13w&#xff0c;去重后3w,B表共2W&#xff0c;且有索引方法一not in&#xff0c;易理解&#xff0c;效率低&#xff0c;时间&#xff1a;1.395sselect distinct A.id …

Quartz 2D编程笔记

当我们需要在一个图形上下文中构建一个路径时&#xff0c;我们需要调用CGContextBeginPath来标记Quartz。然后&#xff0c;我们调用函数CGContextMovePoint来设置每一个图形或子路径的起始点。在构建起始点后&#xff0c;我们可以添加直线、弧、曲线。记住如下规则&#xff1a;…

bitmap算法

博文转载于http://www.cnblogs.com/dyllove98/archive/2013/07/26/3217741.html概述所谓bitmap就是用一个bit位来标记某个元素对应的value&#xff0c;而key即是这个元素。由于采用bit为单位来存储数据&#xff0c;因此在可以大大的节省存储空间算法思想 32位机器上&#xff0c…

Ubuntu下如何解压缩zip,tar,tar.gz,tar.bz2文件

tar解包&#xff1a;tar xvf FileName.tar打包&#xff1a;tar cvf FileName.tar DirName&#xff08;注&#xff1a;tar是打包&#xff0c;不是压缩&#xff01;&#xff09;———————————————.gz解压1&#xff1a;gunzip FileName.gz解压2&#xff1a;gzip -d F…

SELECT INTO 和 INSERT INTO SELECT 两种表复制语句

Insert是T-sql中常用语句&#xff0c;Insert INTO table(field1,field2,...) values(value1,value2,...)这种形式的在应用程序开发中必不可少。但我们在开发、测试过程中&#xff0c;经常会遇到需要表复制的情况&#xff0c;如将一个table1的数据的部分字段复制到table2中&…

向前插入迭代器

**向前插入迭代器&#xff0c;是架构在具有push_front向前插入函数的序列容器&#xff08;比如deque list&#xff09;上的输出迭代器&#xff0c;可以利用*改迭代器提供的“”&#xff0c;“*”&#xff0c;“”以“*fii9;”的类似的形式完成容器元素的赋值。**其中“*”和&qu…

Discuz!X集群部署的系统方案和改造方式讨论

多WEB部署时&#xff0c;面临的核心问题是WEB服务器间的数据共享和同步。就数据存储的方式而言&#xff0c;Discuz数据包含两部分&#xff0c;一部分存储在MySQL数据库中&#xff08;用户、帖子等文本类、结构化的数据&#xff09;&#xff0c;一部分存储为文件&#xff08;附件…

static和extern的用法总结

static用法见&#xff1a; 1、http://www.cnblogs.com/yezhenhan/archive/2011/10/31/2229724.html2、http://www.52rd.com/Blog/Detail_RD.Blog_imjacob_5297.htmlextern用法&#xff1a;1、http://blog.csdn.net/cameracanon/article/details/40614192、http://blog.csdn.net…

给vmware虚拟机中的ubuntu 14.04扩大磁盘分区

一.先取得root 权限 $ su - root Password: su: Authentication failure Sorry. 这时候输入 $ sudo passwd root Enter new UNIX password: Retype new UNIX password: passwd: password updated successfully 这时候就可以进入根目录了。 二.具体安装步骤 用VMware安装了一…

个人管理 - 书籍推荐(待读)

在《个人管理 &#xff0d; 书籍推荐&#xff08;已读&#xff09;》中推荐了一些书籍&#xff0c;有些人从中选取了一些&#xff0c;但其实还有很多好书我还没有读&#xff0c;为了给大家更多选择&#xff0c;我把我欠下的书债也贴上来。由于豆瓣还没有提供书列表的功能&#…

windows7旗舰版序列号[经测试,第一枚即可完成升级!]

windows7旗舰版序列号[经测试&#xff0c;第一枚即可完成升级!] 第一枚&#xff1a;TFP9Y-VCY3P-VVH3T-8XXCC-MF4YK 第二枚&#xff1a;KH2J9-PC326-T44D4-39H6V-TVPBY 第三枚&#xff1a;C4M9W-WPRDG-QBB3F-VM9K8-KDQ9Y 第四枚&#xff1a;J783Y-JKQWR-677Q8-KCXTF-BHWGC 第五…

Node.js用6行代码1个JS文件搭建一个HTTP静态服务器

2019独角兽企业重金招聘Python工程师标准>>> Node.js宣言&#xff1a;Node.js is a platform built on Chromes JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes i…

制作jffs2根文件系统

一、制作mkfs.jffs2工具 首先得准备好两个软件包 &#xff0c;一个是MTD设备的工具包&#xff0c;另一个是zlib压缩包&#xff0c;在这我的MTD设备工具包为mtd-snapshot-20050519.tart.tar&#xff0c;zlib压缩包是zlib-1.2.3.tar.tar。 步骤&#xff1a; &#xff08;1&#…

添加WCF服务引用失败解决办法

最近在玩SL4 beta&#xff0c;写了一个WCF的服务&#xff0c;在Silverlight Application中选择Add Service Reference&#xff0c;填入服务地址&#xff0c;但在生成服务引用代码&#xff08;应该就是代理类&#xff09;时发生错误&#xff1a;Error 7 Custom tool error: Fail…

javascript设计模式简单介绍之【工厂模式】

工厂模式分为两种&#xff0c;一种是简单工厂模式。另一种称之为工厂模式。 简单工厂模式是使用一个外部的单体或者静态方法来生成实例。 而工厂模式使用子类来决定内部成员要实现那个具体的类的实例。 工厂模式要求被具体实现的类&#xff0c;必须提供相同的接口。 下面我们将…

srand函数简介

srand函数是随机数发生器的初始化函数。 原型:void srand(unsigned seed); 用法:它需要提供一个种子&#xff0c;这个种子会对应一个随机数&#xff0c;如果使用相同的种子后面的rand()函数会出现一样的随机数。如:srand(1); 直接使用1来初始化种子。不过为了防止随机数每次重复…

python库--pandas--Series.str--字符串处理

目录 原数据字符大小写转换字符串拼接字符填充/插入/扩展字符串内容判断查找统计转码删减/截取分割/替换原数据 import pandas as pd a pd.Series([aSd, asd, dfd fsAsf sfs]) b pd.Series([None, asd, fgh]) indexab0aSdNone1asdasd2dfd fsAsf sfsfgh字符大小写转换 a.str.l…

linux下多线程之pthread_detach(pthread_self())

写个碰到的问题&#xff0c;记录下自己的技术之路点滴 pthread_detach(pthread_self()) linux线程执行和windows不同&#xff0c;pthread有两种状态joinable状态和unjoinable状态&#xff0c; 如果线程是joinable状态&#xff0c;当线程函数自己返回退出时或pthread_exit时都不…

Unique Binary Search Trees

使用带标记的DP int result[1000];int numTrees(int n) {result[0] 1;result[1] 1;result[2] 2;// Start typing your C/C solution below// DO NOT write int main() functionif(result[n] ! 0)return result[n];int num 0, t;for(t 1; t < n; t){num num numTrees(…

ERROR: Start Page at 'www/index.html' was not found

用Xcode 4.3.2新建了一个PhoneGap的应用&#xff0c;www目录下存在index.html文件&#xff0c;但是运行的时候&#xff0c;报错&#xff1a;ERROR: Start Page at www/index.html was not found&#xff0c;这是PhoneGap和Xcode 4还不兼容导致的。 可以右键项目名->Add File…