多核计算与并发编程 语言篇

转载 2015年11月18日 13:16:34

多核计算与并发编程  语言篇

上一次我们说到,在多核或集群的环境下,可以提高系统整体的吞吐能力,这种架构的设计,和语言是无关的,但是有些语言,具有更好的适应并发环境编程的能力。我在这里把编程语言分四类来讲述它们的差异(为什么只分四类,因为我这里是砖,要等你的玉来补充不是吗)。

第一类,单进程解释语言 python, ruby, node.js等

这类解释语言通常提供极高的开发效率,和相对较差的执行效率,在多核与并发的世界,它们不提供任何支持。执行一段代码时,无法使用到第二个cpu内核。所以执行这类语言开发的服务,想要利用所有的cpu,只能依靠架构和部署。

在多核和集群的环境下,这类语言的部署是类似的,就是启动多个进程,各自独立地响应服务请求,来提升系统整体的并发吞吐能力,对外接口方面,需要硬件或者软件的负载均衡代理层。如果有进程内的可变缓存对象,开发时需要考虑数据同步。

第二类,共享内存的多线程语言 java, .net等

这类语言在设计之初都注重性能,具有较高的执行效率。在单核的年代,他们提供了创建操作系统线程的能力,可以在一个运行进程内,充分利用cpu的运算能力(当一个空闲线程等待时,其它的线程可以运行)。当多核cpu发明以后,那些支持多线程的软件,自动就具有了支持多核的能力。然而多核出现是在这类语言发明之后,真正的并发执行发生后,原先单核环境下不会发生的问题暴露出来,于是java和.net纷纷升级语言,提供补丁,以更好的支持多核并发的环境。

那么,并发执行暴露出来的是什么问题。通常是因为并发执行的进程访问了共享的内存,由于读写的次序不可预料,会产生不可预料的结果。怎么解决这个问题,java和.net提供的方法是加锁,就是到一个进程(线程)访问共享内存时,不允许其它进程(线程)访问。写加锁的代码对程序员的要求很高,一不小心就会发生死锁,而一旦发生死锁,排查错误非常困难。

在架构方面,在多核的单台服务器环境下,不需要运行多个进程也能提高吞吐能力,简化了部署。在集群环境下,和第一类语言相同。

第三类,不共享内存的多线程语言 Erlang

Erlang诞生已经二三十年,设计之初,是为集群设计,提供了集群与单机一致的开发方法,从语言层面,消除了单机和集群的差异。用Erlang在单机开发的软件,可以轻松扩展运行在整个集群上。这是架构层面的简化。

Erlang是函数式语言,变量只能赋值一次,然后不可改变,同时,Erlang不允许进程间共享数据,从语言层面避免的并发编程最容易引起的错误。因为进程间不允许共享数据,所以Erlang也不需要加锁解锁的语句,我猜语言本身在底层实现用到了加锁原语,但程序员可以和繁复的锁告别,是足够幸福的。每个进程都可以安全的并发执行,但在进程内部,所有的操作都是串行的。往好处想,既享受到了多核和集群的好处,又避免了产生编程错误的可能,正是目前Erlang持续升温的原因。不足的地方是,不适合某些场景的应用,比如缓存服务,当我有一大块内存提供缓存服务时,只能有一个进程来读写这块内存,无法进一步提升服务性能。

第四类,为并发设计的混合式语言 Golang

在介绍Golang之前,先总结Erlang适应多核编程的特点

  1. 单个服务能利用到多核

  2. 进程间不共享内存

  3. 进程间用消息通讯,不用加锁机制

  4. 进程间可以跨服务器通讯

之前我们说的第一类语言比如python,不能做到第一点。第二类语言java和.net,不能做到第三点,所有的语言都不能做到第四点(需要额外开发,不能在语言内部支持)。

如果以Erlang的思想来写Golang的代码,可以做到1,2,3点。你大概能知道Golang是怎么回事了。

Go语言的特色是,很多事情你都“可以”做。可以进程间使用消息管道来替代锁,也可以使用锁。可以使用函数式编程,也可以使用面向对象开发。可以共享内存,当然开发人员可以选择不共享内存。可以方便创建多个进程来并发执行,也可以指定最多的并发数目,限制cpu资源消耗。

参考Erlang的设计思想,我们开发Go语言应用时,可以做到“1”和“3”,便利地使用多核来提高性能,同时降低开发门槛。在我们《架构篇》中提到的场景,网页服务的场景可以做到“2”,进程间不共享内存;而缓存服务的场景,我们可以使用多进程来访问读取共享缓存,提高吞吐能力,而同时保证只存在一个进程,来修改共享缓存,避免写入冲突。

注意,这里有个边界状况,你需要留意,而我在这里忽略了。也就是写入操作完成一半时,可能被读取进程读到不完整的数据,在我这里的场景,并不太在乎。如果一定要保证读取数据一致,将不得不引入加锁机制,这是多么可怕。

在下一篇,我会讲讲怎样用Erlang的思想写Go语言的代码

为多核环境创造并行编程语言

作者:Ed Sperling软件开发往往滞后于硬件的变革速度,尤其在多核芯片领域这种差距还在不断扩大。硬件方面,在合理功耗条件下进一步发掘130纳米乃至65纳米单核处理器的性能潜力已变得极为困难。在笔...

C++多核高级编程 - 09 并发模型之 一 Boss-Worker

Boss-Worker 之前有过一些介绍,下面将用图示的方式介绍一些这个模型,及它的一些演化结构。 一,Boss-Worker 使用方法1 Boss为每个任务创建新线程或进程这些任务可以并...

IOS中的多核并发编程GCD

Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。 dispatch queue分成以下三种: 1)运行在主线程的Main queue,通过disp...

C++多核高级编程 - 06 并发任务的通信和同步(1) 通信和同步

一, 依赖关系 当进程或线程相互之间要求通信或协作完成一个共同的目标时,他们之间便存在了依赖关系。 通信依赖:当TaskA要求来自TaskB的数据才能执行它的工作时,TaskA和TaskB...

C++多核高级编程 - 06 并发任务的通信和同步(3) 线程的策略方法及工作的分解和封装

一 , 线程的策略方法 线程的策略决定了在将应用程序线程化时可能使用的方法。方法决定了被线程化的应用程序如何将它的工作委派给任务及通信如何进行。 常见的模型: 委托(boss-worke...

并行计算简介和多核CPU编程Demo

作者: 侯思松 (1 篇文章) 日期: 五月 5, 2009 在 5:18 下午 http://software.intel.com/zh-cn/blogs/2009/05/05/cpudemo...

并行计算简介和多核CPU编程Demo

tag:多线程,并行计算,OpenMP,多核编程,工作线程池 ( 2008.01.19 更新  鉴于读者反映代码阅读困难,重新改写了文章和实现,使文章更易读 ) ( 2007.09.04 ...
  • cbNotes
  • cbNotes
  • 2014年08月26日 11:18
  • 4809

并行计算简介和多核CPU编程Demo

    2006年是双核的普及年,双核处理器出货量开始超过单核处理器出货量;2006年的11月份Intel开始供货4核;AMD今年也将发布4核,并计划今年下半年发布8核;    按照Intel一个文档...
  • Augusdi
  • Augusdi
  • 2011年03月31日 14:36
  • 1342

IOS中的多核并发编程GCD

Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。 dispatch queue分成以下三种: 1)运行在主线程的Main queue,通过...

顺序性,一致性,原子性:现代多核体系结构与原子操作·CAS与自旋锁·自旋锁与并发编程的原语·语句原子性和编程逻辑的原子性·行锁与数据库事务原子性·binlog与数据库同

顺序性: 乱序执行·逻辑正确性  现代体系结构的每一个核的指令流水是乱序执行的,但是他能够保证其执行效果等同于顺序执行。 一致性: 各核及线程缓存·volatile 各核缓存及线...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:多核计算与并发编程 语言篇
举报原因:
原因补充:

(最多只允许输入30个字)