并发之美,告诉我你是几核的

    并发编程很难控制,虽然目前java、android、go、erlang都提供了多线程处理方案,但仍未能解决所有问题。另外,在并发控制需要考虑的问题有:运行速度,安全性,代码清晰性。

    每个在系统运行的程序至少包含一个进程,每个进程可以包含一到多个线程。在单个进程中运行多个线程以达到完成不同工作的目的,称之为多线程。操作系统大多是分时设计,也就是把连续的指令流分成一片片的指令。硬件提供一个定时器,时间一到,就告诉操作系统该换一片指令流了。因为每秒可以这样切换很多次,给用户的感觉是在同时运行,也即是并发。这种设计类似于一个餐厅里面,只有一个服务员,这时候同时来了三桌的客人,如果先给第一桌上齐菜再服务其它,最后一桌的客人肯定不满意,说不定还砸桌子。现在有了分时设计的理念,就好办多了,服务员第一次先给第一桌客人上一盘菜,让他们吃着先,接着次序去给第二,第三桌上………这样就谁都不怠慢了。虽然在客人眼里貌似是不需要等待,其实服务员的工作效率还是没改变。如果餐厅能够多招几个服务员,这样就更好了。如果一个问题有解决的价值,那么就会有人去解决它。计算机也有了类似机制:多核与分布式。多核、分布式与多线程的结合能够更大程度上提高用户体验,就好比餐厅的服务员不再是一个,而是更多,服务客户的速度更快了。基于多核、分布式只是类似于增加服务员,单个CPU处理方式依然没有改变,所以以下的介绍以单核为例子。

    现在说说各个语言处理并发的问题,在java语言中,使用多线程处理高并发问题,给人第一感觉就是笨重,实际上也是如此。java中有两种方法创建线程(1)扩展java.lang.Thread类(2)实现java.lang.Runnable接口。java创建的线程,系统内存开销较大,影响运行速度。而且线程数目一般限制于几十个之内,虽然能够使用线程池达到线程复用的目的,但是仍没能根本改变系统内存开销过大的问题。java多线程中会涉及访问同一数据的情况,也就是线程同步问题。举个例子:邻居家有一个漂亮姑娘,小王跟小李都分别拜托媒人去说媒。小李的媒人去跟姑娘的爸爸沟通后,回去准备聘礼。结果这事被小王知道,他赶紧让媒人抢先一步把聘礼带过去,两家的小伙子都一样好,两家的媒人情面都一样大,只好聘礼先到的成事,姑娘爸爸也只好拒绝了小李,从此小王和姑娘快乐在一起了。如果开始时候姑娘的爸爸先在门口贴个告示:“我家姑娘接受说媒”,在媒人进入家门的时候,媒人就可以把告示取下。当媒人和姑娘的爸爸谈好后,姑娘爸爸就会在家门口贴个告示说“我家姑娘已经答应某某某,别家不要再来了”那么小王就没机会了。相同,java中设计了同步机制保护,专门处理多线程同步的问题:在任何一个java对象,都有唯一的锁标志。线程访问对象前,先取得锁标志,在线程离开锁标志的关键代码端之后,才会归还锁标志,也就是在该线程没有处理完之前,其它线程是无法访问该对象。锁机制也容易引发线程阻塞问题,类似于姑娘家的爸爸,他有一个一次只接待一位客人的习惯他在接待小李的媒人的时候,小王的媒人只好等待,直到小李的媒人走后才能和姑娘爸爸谈。线程阻塞也一样,两个线程同时需要某个对象,先到先得,其它线程只好等待。

    在android中,线程处理问题与java是一脉相承,基本上可以说是没多大改动,只是在Thread、Runnable的基础上,增加AsyncTask为android提供的轻量级的异步操作。android中使用AsyncTask能够让代码的结构清晰,有助于阅读。

    go语言算是为并发问题而生,以其简洁的风格,解决并发编程的大难题。在go中需要了解两个概念,协程与通道。协程是轻量级的线程,通道是协程之间传输数据的通道。在面向过程编程中,调用一个过程的时候,程序通常需要等待执行完成才返回。调用协程不需等待程序执行完,即可返回。在go中,可以在一个进程中执行数十万的协程,依旧保持高性能。同样情况下的java平台,如果有数百个线程,足以让CPU奔溃。go语言通道有两种使用方法:(1)协程可以试图向通道放入数据,如果通道满了,会挂起协程,直到通道可以为他放入数据为止。(2)协程可以试图向通道索取数据,如果通道没有数据,会挂起协程,直到通道返回数据为止。通道控制着协程的运行。通道的使用方法, 保证数据使用的安全性。

    erlang平台与go一样,也是处理高并发的优秀语言。它的设计理念之一就是为了解决高并发问题,这里引入它的设计哲学:(1)世界是并发的(2)事物之间不共享数据(3)事务通过消息进行通信(4)事务会出现故障。erlang就是为每个事件生成一个新轻量级进程(注意go是生成协程,轻量级的线程),通常使用轻量级进程,几十万甚至上百万进程同时并发使用的内存也不多。每个erlang进程都用用来存储传入信息的信箱,用以实现进程间的通信。当一个消息发送的时候,它会从发送进程复制到接收信箱以便于检索。发送信息是永远不会失败,就算是发送给一个不存在的进程,它也只会被丢弃。同时发送信息是异步的:发送进程不会在发送信息后被暂停,它会继续执行其代码的下一个表达式。在执行接收信息的时候,按照时间(先进先出原则)依次匹配,匹配成功则执行匹配部分,不成功则继续匹配,直至匹配完所有信息。

    这里引用一句话“数学家站在彼此肩上,计算机科学家踩在彼此脚尖上”各个语言都有其优缺点,至于语言之中的抉择,因需而定。


作者:

卡卡秀团队——MiddlePan

欢迎转载与评论~


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值