多线程

来源:互联网 发布:双色球万能矩阵必中6码 编辑:程序博客网 时间:2024/05/22 00:55

参考

多线程

线程是操作系统直接支持的执行单元
启动一个线程就是把一个函数传入并创建Thread实例,然后调用start()开始执行:

# -*- coding:utf-8 -*-import threadingimport timedef loop():    print 'thread %s is runing...' % threading.current_thread().name    n = 0    while n<5:        n = n+1        print 'thread %s >>> %s' %(threading.current_thread().name,n)        time.sleep(1)print 'thread %s is runing...' % threading.current_thread().namet = threading.Thread(target = loop,name = 'LoopThread')t.start()t.join()print 'thread %s ended ' % threading.current_thread().name

thread MainThread is running...#主线程执行thread LoopThread is running...#子线程执行thread LoopThread >>> 1thread LoopThread >>> 2thread LoopThread >>> 3thread LoopThread >>> 4thread LoopThread >>> 5thread LoopThread ended.thread MainThread ended.        #主线程执行

主线程
进程默认就会启动一个线程,该线程称为主线程
主线程又可以启动新的线程
current_thread()
Python的threading模块有个current_thread()函数,它永远返回当前线程的实例。

主线程实例的名字叫MainThread,子线程的名字在创建时指定,用LoopThread命名子线程
t = threading.Thread(target = loop,name = 'LoopThread')

Lock

多线程和多进程最大的不同
多进程中,同一个变量,各自有一份拷贝存在于每个进程中,互不影响,
而多线程中,所有变量都由所有线程共享,所以,任何一个变量都可以被任何一个线程修改,
因此,线程之间共享数据最大的危险在于多个线程同时改一个变量,把内容给改乱了。

# -*- coding:utf-8 -*-import threadingimport timebalance = 0def change_it(n):    global balance    #先加后减应为零    balance = balance + n    balance = balance - ndef run_thread(n):    for i in range(100000):        change_it(n)t1 = threading.Thread(target = run_thread,args=(5,))t2 = threading.Thread(target = run_thread,args=(8,))t1.start()t2.start()t1.join()#主线程调用了ti.join()-->在该处等待t1子线程完成操作才能继续执行t2.join()print balance

高级语言的一条语句在CPU执行时是若干条语句,即使一个简单的计算:
balance = balance + n
也分两步:

1. 计算balance + n,存入临时变量中;2. 将临时变量的值赋给balance。

看成:

x = balance + nbalance = x

代码正常执行时:

初始值 balance = 0t1: x1 = balance + 5 # x1 = 0 + 5 = 5t1: balance = x1     # balance = 5t1: x1 = balance - 5 # x1 = 5 - 5 = 0t1: balance = x1     # balance = 0t2: x2 = balance + 8 # x2 = 0 + 8 = 8t2: balance = x2     # balance = 8t2: x2 = balance - 8 # x2 = 8 - 8 = 0t2: balance = x2     # balance = 0结果 balance = 0

t1和t2是交替运行的,如果操作系统以下面的顺序执行t1、t2:

初始值 balance = 0t1: x1 = balance + 5  # x1 = 0 + 5 = 5t2: x2 = balance + 8  # x2 = 0 + 8 = 8t2: balance = x2      # balance = 8t1: balance = x1      # balance = 5t1: x1 = balance - 5  # x1 = 5 - 5 = 0t1: balance = x1      # balance = 0t2: x2 = balance - 5  # x2 = 0 - 5 = -5t2: balance = x2      # balance = -5结果 balance = -5

究其原因
是因为修改balance需要多条语句,而执行这几条语句时,线程可能中断,从而导致多个线程把同一个对象的内容改乱了。

确保balance计算正确
就要给change_it()上一把锁,当某个线程开始执行change_it()时,我们说,该线程因为获得了锁,因此其他线程不能同时执行change_it(),只能等待,直到锁被释放后,获得该锁以后才能改。
同一时刻最多只有一个线程持有该锁,所以,不会造成修改的冲突。创建一个锁就是通过threading.Lock()来实现:

balance = 0lock = threading.Lock()def run_thread(n):    for i in range(100000):    #先获取锁    lock.acquire()    try:        change_it(n)    finally:        #一定释放        lock.release()

多个线程同时执行lock.acquire()时,只有一个线程能成功地获取锁,然后继续执行代码,其他线程就继续等待直到获得锁为止。

获得锁的线程用完后一定要释放锁,否则那些苦苦等待锁的线程将永远等待下去,成为死线程

try...finally来确保锁一定会被释放

阻止了多线程并发执行

join()

join ()方法:主线程A中,创建了子线程B,并且在主线程A中调用了B.join(),那么,主线程A会在调用的地方等待,直到子线程B完成操作后,才可以接着往下执行,那么在调用这个线程时可以使用被调用线程的join方法。
join([timeout])
参数时可选的,代表线程运行的最大时间,即如果超过这个时间,不管这个此线程有没有执行完毕都会被回收,然后主线程或函数都会接着执行的。
主进程挨个调用子线程的join()方法。当四个线程都执行完毕后,主线程才会执行下面的代码,在这里也就是退出了。

setDaemon()

setDaemon,在底层的thread模块中,只要 主线程结束了,所有的 其它线程都会结束,这很明显,主线程结束python将销毁运行时环境,主线程肯定会被结束。
threading模块的线程setDaemon就是为了解决这个问题的setDaemon(True),那么和之前一样,主线程结束,所有子线程都将结束
setDaemon(False),主线程将等待该线程结束,等同于你调用线程的join方法。

原创粉丝点击