惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 叶小钗
D
Darknet – Hacking Tools, Hacker News & Cyber Security
S
SegmentFault 最新的问题
博客园 - 三生石上(FineUI控件)
雷峰网
雷峰网
WordPress大学
WordPress大学
有赞技术团队
有赞技术团队
博客园 - 【当耐特】
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
V2EX
V
Visual Studio Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 聂微东
P
Proofpoint News Feed
Last Week in AI
Last Week in AI
U
Unit 42
W
WeLiveSecurity
博客园 - Franky
Recent Announcements
Recent Announcements
Hacker News - Newest:
Hacker News - Newest: "LLM"
Attack and Defense Labs
Attack and Defense Labs
月光博客
月光博客
The Cloudflare Blog
Spread Privacy
Spread Privacy
腾讯CDC
P
Privacy International News Feed
N
News and Events Feed by Topic
AWS News Blog
AWS News Blog
NISL@THU
NISL@THU
T
Troy Hunt's Blog
小众软件
小众软件
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Microsoft Security Blog
Microsoft Security Blog
L
Lohrmann on Cybersecurity
Webroot Blog
Webroot Blog
Y
Y Combinator Blog
量子位
P
Palo Alto Networks Blog
N
News and Events Feed by Topic
V
Vulnerabilities – Threatpost
K
Kaspersky official blog
IT之家
IT之家
T
Threat Research - Cisco Blogs
Cloudbric
Cloudbric
云风的 BLOG
云风的 BLOG
C
Check Point Blog
Blog — PlanetScale
Blog — PlanetScale
爱范儿
爱范儿
G
Google Developers Blog
S
Secure Thoughts

博客园 - wsky

生产环境使用Nuget 为WebClient增加Cookie支持 keepalived安装和使用 NHibernate分享 PPT 开源选型关注点 SocketAsyncEventArgs stunnel+haproxy SSL以及问题记录 快速实现一个简单的bigpipe模型 Velocity2010大会回顾 小结一下关于bpm实施方面的交流 乱弹之企业应用 互联网企业流程部门价值方向的一些探讨 Live Writer的代码插件 再谈团队,项目,产品 【渐进】关于反向代理,负载均衡 【渐进】浅尝DDD,对"试卷"建模 【渐进】延迟加载机制的简易实现(上) - wsky - 博客园 略谈“开发效率” 分工,协作,团队
【渐进】设计一个模拟并行的线程同步组件
wsky · 2009-12-23 · via 博客园 - wsky

    您是否遇到下述几个场景:

    1. 一个算法中有些步骤希望可以并行执行以提高计算效率。
    2. 在一个工作流中,其中一个活动执行完毕后进入多个并行的分支活动,所有分支活动处理完毕后再返回主流程继续下一个活动。

     本文就将针对上述场景的需求设计一个组件来支持您的设计。

     从以上的几个场景我们可以分析出其需求:

“主线程执行中途,需要等待几个子线程的处理结束后,继续主线程的执行。”

     于是,我们将依据此设计一个能满足此特性的组件,也许您已经想到可以简单的利用事件等通知机制来让子线程执行完毕后发出通知然后进行下一步操作:

image

     上图描述了利用事件,消息等机制后形成的执行模型。

     再来看一下这张图:

image

     您是否希望让主/子线程编程能在一个方法区域内保持线性的语法书写,而不是通过Callback等方式打乱原本的书写顺序和连贯性?

     瞻仰并行

     dotnet3.5开始提供了并行计算的支持,PLinq就是Linq的并行版本,在System.Theading空间(是一个单独的并行库System.Theading.dll)下,4.0则极大的增强了并行编程的支持。PLinq给我们提供了如下的启用并行的语法对集合进行遍历:

  1. new List<object>().AsParallel().ForAll(o => { });

测试一下:

  1. var p = new List<Action>(){() => { Thread.Sleep(1000); Console.WriteLine("子任务1完成"); }
  2.                 , () => { Thread.Sleep(1000); Console.WriteLine("子任务2完成"); }
  3.                 , () => { Thread.Sleep(1000); Console.WriteLine("子任务3完成"); }
  4.                 , () => { Thread.Sleep(1000); Console.WriteLine("子任务4完成"); }
  5.                 , () => { Thread.Sleep(1000); Console.WriteLine("子任务5完成"); }
  6.                 , () => { Thread.Sleep(1000); Console.WriteLine("子任务6完成"); }
  7.                 , () => { Thread.Sleep(1000); Console.WriteLine("子任务7完成"); }}.AsParallel();
  8.             DateTime begin = DateTime.Now;
  9.             p.ForAll(O => O());
  10.             Console.WriteLine("?时" + (DateTime.Now - begin).TotalMilliseconds);
  11.             begin = DateTime.Now;
  12.             p.ForAll(O => O());
  13.             Console.WriteLine("?时" + (DateTime.Now - begin).TotalMilliseconds);

image

     上述代码的执行效率,根据CPU的核心数,能提高几乎相同的倍数。事实上3.5对并行的支持只算是一个初步的预览。设计使用不当,未必能带来多少的提升。其实现原理同样是利用多线程,并且System.Theading中提供专用的线程池来优化线程的利用。

     回到我们的主题上来,上文所确立的需求有点类似并行处理,这是执行行为上类似,不过设计目标还是有所不同的,我们旨在设计线程同步组件,来支持主子线程的同步和语法上的流畅,而并行计算的目的是尽可能的利用CPU的计算能力。

      既然是要进行线程同步,就要有相应的同步机制,这里采用了WaitHandle(可参考http://msdn.microsoft.com/zh-cn/library/system.threading.waithandle(VS.80).aspx)来完成这个设计。 关于AutoResetEvent和ManualResetEvent,二者都派生自WaitHandle,类似信号灯的作用,二者区别在于前者会自动唤醒一个线程,后者可编程控制唤醒多个线程。

      文章后面将附上代码下载,设计仍有可改进的空间,如线程的利用等。

调用语法:

  1. //create
  2. var paralle = Paralle.Create();
  3. //add task
  4. paralle.Add(() => { Thread.Sleep(1000); });
  5. //start
  6. paralle.Begin();
  7. //return main thread
  8. //...

测试代码:

  1. Console.WriteLine("并?模拟组件测??");
  2. Console.WriteLine("主任务开始。");
  3. Thread.Sleep(5000);
  4. Console.WriteLine("主任务暂停。");
  5. Console.WriteLine("");
  6.  
  7. //第一次使用
  8. DateTime begin = DateTime.Now;
  9.  
  10. var p = Paralle.Create();
  11. p.Add(() => { Thread.Sleep(1000); Console.WriteLine("子任务1完成"); }
  12.     , () => { Thread.Sleep(1000); Console.WriteLine("子任务2完成"); }
  13.     , () => { Thread.Sleep(1000); Console.WriteLine("子任务3完成"); }
  14.     , () => { Thread.Sleep(1000); Console.WriteLine("子任务4完成"); });
  15.  
  16. Console.WriteLine("初始化?时(ms)?" + (DateTime.Now - begin).TotalMilliseconds);
  17. begin = DateTime.Now;
  18.  
  19. p.Begin();
  20.  
  21. Console.WriteLine("执??时(ms)?" + (DateTime.Now - begin).TotalMilliseconds);
  22.  
  23. Console.WriteLine("");
  24. Console.WriteLine("主任务继续。");
  25. Thread.Sleep(2000);
  26. Console.WriteLine("主任务暂停。");
  27. Console.WriteLine("");
  28.  
  29. //第二次使用
  30. p.Clear();
  31.  
  32. begin = DateTime.Now;
  33.  
  34. p.Add(() => { Thread.Sleep(1000); Console.WriteLine("子任务5完成"); }
  35.     , () => { Thread.Sleep(1000); Console.WriteLine("子任务6完成"); }
  36.     , () => { Thread.Sleep(1000); Console.WriteLine("子任务7完成"); }
  37.     , () => { Thread.Sleep(1000); Console.WriteLine("子任务8完成"); });
  38.  
  39. Console.WriteLine("初始化?时(ms)?" + (DateTime.Now - begin).TotalMilliseconds);
  40. begin = DateTime.Now;
  41.  
  42. p.Begin();
  43.  
  44. Console.WriteLine("执??时(ms)?" + (DateTime.Now - begin).TotalMilliseconds);
  45. Console.WriteLine("");
  46.  
  47. Console.WriteLine("主任务结束。");

结果:

image

如上图所示,主任务暂停后,等待子任务执行完毕就继续执行紧接着的代码段(即主任务)。

代码下载地址:/Files/wsky/ParalleV1.0.rar