多线程总结
话说多线程认识让我恼火了一阵子,很是不习惯程序跳来跳去的执行,毫无时间和空间逻辑的感觉了,现在对我所见的总结一下吧,其实多线程呢在目前的语言中都是差不多,所以只要你理解了多线程在任何语言都是使用的,不同的就是语法不同而已吧
1. 多线程内幕:
什么是多线程,说白了就是多个线程并发的执行, 既然是并发执行,但是cpu是不可能同时执行多个线程吧,所以怎么办呢,其实是一个假象,由于cpu的时间片轮转的特别快,所以误以为为并发
2. 从1中我们知道了一个问题
就是并发还有cpu轮转就导致线程执行失去了空间和时间顺序,当失去这两个的时候,那么被多线程操作的数据就悲剧了,数据的变化就跟cpu的状态有关了,显然不是很中意的感觉,所以我们引进了锁的概念。什么是锁? 这里的锁不是把线程锁到一个牢房里面而限制这个线程运行, 而相反,当某个线程被锁住了才有执行的权利,否者就是处于阻塞状态,什么是阻塞请看第三点, 既然锁有这个功能,那么我们就可以锁住某个线程,在这个线程被锁住的时间段内,cpu就只处理这个线程, 这样就可以控制时间和空间了,至少这样给了一点儿自己控制的欲望,哈哈
3.什么是阻塞
记得一直不理解,现在就总结一下吧。 阻塞的意思就是被阻挡,被阻挡在什么地方呢?这个问题没有人告诉我,也没看到过,结果就我只是意淫吧, 我认为分两种情况,情况一就是这个线程处于锁定池中,那么线程就被阻挡于cpu的门外,只有等 cpu(纯属拟物表达)里面的线程执行完毕才有机会(只是有机会,因为锁定池里面可是一池子的线程等待呀);情况二就是线程压根儿就没有进锁定池,还是处于等待池(这个待会儿解释)中,这个时候离被执行的时间还长着了,就相当于被阻挡于锁定池外吧
4,锁定池是什么呢?
就是在cpu门外排队的院子,院子里面估计随时都站了很多人。什么是等待池呢?就是连院子都还没有进,就更别说cpu的大门了,只有cpu通知院子外面的人进来他们才能进来5.还谈谈线程同步的问题吧,其实就是上面说的第2点,是靠锁解决6.谈谈什么是线程通讯的问题,也就是上面谈得连院子都还没进的人什么时候进入院子的事儿。这个问题转化为正在执行的这个线程在cpu中执行完之后标记一个条件变量(就一变量),这个变量就是通知院子外的线程可以升级了,在院子里面来接着等吧(呵呵)
5.这个地方还有我另外一段的总结, 放这里吧,相信对你也是有帮助的:
线程总结2:
1.线程是分为五种状态的, 新建,就绪,运行,阻塞,死亡
2.为了使数据同步,所以有了线程同步(就是当数据是一个共享数据时,将数据锁住,只允许锁定这个数据的线程使用,别的线程处于等待状态
(就是阻塞状态))这个功能
(就是阻塞状态))这个功能
3. 数据能被线程操作就必须得现有数据(必须的),如果数据是由线程一在运行后创建的, 那么线程二,三,四...就只能等线程一先执行后才能
执行(否则就没有供线程2,3,4...操作的数据),为了达到让线程先后执行的目的就引入了线程之间的通讯机制,也就是设一个条件变量,只
有当 线程一执行后设定条件变量为可行(我感觉是自己(线程一)执行完毕)时,此时等待池(此处线程状态为等待)里面的线程才能进入
锁定池 (此时线程为暂停,或者是阻塞)变为阻塞状态
执行(否则就没有供线程2,3,4...操作的数据),为了达到让线程先后执行的目的就引入了线程之间的通讯机制,也就是设一个条件变量,只
有当 线程一执行后设定条件变量为可行(我感觉是自己(线程一)执行完毕)时,此时等待池(此处线程状态为等待)里面的线程才能进入
锁定池 (此时线程为暂停,或者是阻塞)变为阻塞状态
4. 这一点是对3的一个更正, 以前对3是理解不清楚的,其实等待池和锁定池里面的进程都是阻塞的,下面引入一个大牛的回复:
技术上处于等待池和锁定池中的线程都是传统意义上的阻塞状态,只不过为不同的对象所阻塞而已。
等待池是等待一个事件的发生(条件变量),比如等待磁盘I/O的完成,等I/O完成后,会通知一个或全部之前等待的线程,于是这些线程进
入锁定 池,同样也是阻塞状态。为什么不直接进入运行状态(已锁定)?因为所有线程共享一个mutex/lock,只有锁定池中的一个可以线
程幸运的获得 锁,进入已锁定状态。所以,等待池中的线程等的是条件变量的触发,锁定池中的线程等的是获得共享锁。这些都是条件变
量的特点。
等待池是等待一个事件的发生(条件变量),比如等待磁盘I/O的完成,等I/O完成后,会通知一个或全部之前等待的线程,于是这些线程进
入锁定 池,同样也是阻塞状态。为什么不直接进入运行状态(已锁定)?因为所有线程共享一个mutex/lock,只有锁定池中的一个可以线
程幸运的获得 锁,进入已锁定状态。所以,等待池中的线程等的是条件变量的触发,锁定池中的线程等的是获得共享锁。这些都是条件变
量的特点。
哈哈,下面这个例子一...告诉我的例子,话糙理不糙呀:
举个少儿不宜的例子,等待池中的线程就像爸爸身体里的上亿个精子,蠢蠢欲动等待爸爸妈妈结合的那一刻 ---> 爸爸妈妈结合的那一刻,精
子们终于等到了通知,一个激动全部冲入妈妈的肚子里,此时进入等待锁定池,等待着和妈妈的卵子结合! ---> 最终只有一个幸运的精子可
以得到卵子的垂青,结合在一起!此时就是已锁定状态!
子们终于等到了通知,一个激动全部冲入妈妈的肚子里,此时进入等待锁定池,等待着和妈妈的卵子结合! ---> 最终只有一个幸运的精子可
以得到卵子的垂青,结合在一起!此时就是已锁定状态!
此线以后就是跟python有关了
1.python的time.sleep(val)是干什么的呢
可不是网上很多没说清楚的使主线程睡眠val秒,而是这句处于哪个正在执行的线程代码中,那么这个线程就得睡眠val秒,睡眠的意思就是睡觉休
息了,休息了的这段时间cpu课不能闲着呀, 还得去执行别的线程,等休息了val秒后接着执行(个人感觉别的线程可不是那么容易的将执行权还
给这个线程,应该会拖拖拉拉的)
息了,休息了的这段时间cpu课不能闲着呀, 还得去执行别的线程,等休息了val秒后接着执行(个人感觉别的线程可不是那么容易的将执行权还
给这个线程,应该会拖拖拉拉的)
2. thread模块只能提供简单的锁
很多缺点我不说了,除非你是绝对的高手,否则还是别玩这个了,玩另一个吧
3.threading,高度成熟的一个库
在thread基础上封装了很多高级的类
下面我着重介绍一下threading模块的使用:
三种不同的创建线程方法
方法1:
就是直接用像thread模块一样吧,传入一个函数,这里就不给出源码了
方法2:
用面向对象的模式创建一个线程实例,说白了就是不再是给线程传递一个将要执行的函数了,而是传递一个实例对象,你在想一个对象里面类么多方法,究竟要执行类里面的哪一个方法呢?这个问题看实例吧
#encode:utf-8 import thread import threading import time def ClassFunc(object): def ___init__(self, func, args, name): self.name = name self.func = func self.args = args def __call__(self): apply(self.func, self.args, self.name) loops = [2, 4] def loop(n, nsec): print 'loop ', n, 'start at :', time.time() time.sleep(nsec) print 'loop ', n, 'done at :', time.time() def main(): nloops = range(len(loops)) threads = [] for i in nloops: print nloops[i] t = threading.Thread(target = loop, args = (i, loops[i])) threads.append(t) print 'all loop start at:', time.time() for i in threads: i.start() for i in threads: i.join() print 'all loop done at:', time.time() if __name__ == '__main__': main()
上面的问题答案就是将自动调用方法__call__,这个方法就是为线程专门设计,大家也看到了__call__这个方法里面有一条apply(...)了吧,其实这个函数的作用就是调用存于元组或者字典里面的方法,现在self.func, self.args, self.name 里面就是一个完整的方法,有方法名,参数列表,线程名字
方法3:
#coding=gbk import threading, time, random count = 0 class Counter(threading.Thread): def __init__(self, lock, threadName): '''@summary: 初始化对象。 @param lock: 琐对象。 @param threadName: 线程名称。 ''' super(Counter, self).__init__(name = threadName) self.lock = lock def run(self): '''@summary: 重写父类run方法,在线程启动后执行该方法内的代码。 ''' global count self.lock.acquire() for i in xrange(100000000): count = count + 1 self.lock.release() lock = threading.Lock() for i in range(5): Counter(lock, "thread-" + str(i)).start() time.sleep(5) print count
方法三代码引用自:http://blog.csdn.net/jgood/article/details/4305604,解释看这里吧
未完待续