python提供了两个模块来实现多线程thread 和threading ,thread 有一些缺点,在threading 得到了弥补,为了不浪费时间,所以我们直接学习threading 就可以了。
Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import threading 5 import time 6 7 def show(arg): 8 time.sleep(1) 9 print 'thread'+str(arg) 10 11 for i in range(10): #开启10个线程 12 t = threading.Thread(target=show, args=(i,)) #创建线程t,使用threading.Thread()方法,在这个方法中调用show方法target=show,args方法对show进行传参。 13 14 t.start() 15 print 'main thread stop'
上述代码创建了10个“前台”线程,然后控制器就交给了CPU,CPU根据指定算法进行调度,分片执行指令。
python中的多线程,有一个GIL(Global Interpreter Lock 全局解释器锁 )在同一时间只有一个线程在工作,他底层会自动进行上下文切换.这个线程执行点,那个线程执行点!
更多方法:
start() 线程准备就绪,等待CPU调度
setName 为线程设置名称
getName 获取线程名称
setDaemon setDaemon(True)将线程声明为前台线程,必须在start() 方法调用之前设置
如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止
如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止
join 逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得无意义
run 线程被cpu调度后执行Thread类对象的run方法
线程锁
由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,CPU接着执行其他线程。所以,可能出现抢占屏幕打印问题,出现乱序问题,执行上面的代码可以直接看到效果.所以就出现了线程锁机制,专门解决这个问题.
设置线程锁
python的锁可以独立提取出来
#锁的使用 #创建锁 lock= threading.Lock() #锁定 lock.acquire([timeout])#锁定方法acquire可以有一个超时时间的可选参数timeout。如果设定了timeout,则在超时后通过返回值可以判断是否得到了锁,从而可以进行一些其他的处理。 #释放 lock.release()
设置线程锁:
1 #!/usr/bin/env python 2 #coding:utf-8 3 4 import threading 5 import time 6 7 gl_num = 0 8 lock = threading.RLock() #创建线程锁 9 10 def Func(): 11 lock.acquire() #锁定 12 global gl_num 13 gl_num +=1 14 time.sleep(1) 15 print gl_num 16 lock.release() #释放锁 17 18 for i in range(10): 19 t = threading.Thread(target=Func) 20 21 t.start()
event
他的作用就是:用主线程控制子线程合适执行,他可以让子线程停下来,也可以让线程继续! 他实现的机制就是:标志位“Flag”
事件处理的机制:全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,那么event.wait 方法时便不再阻塞。
clear:将“Flag”设置为False
set: 将“Flag”设置为True
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import threading 5 6 def do(event): 7 print 'start' 8 event.wait() #执行对象wait方法,然后他们停下来,等待“Flag”为True 9 print 'execute' 10 11 event_obj = threading.Event() #创建事件的对象 12 13 for i in range(10): 14 t = threading.Thread(target=do, args=(event_obj,)) #把方法do传到每个线程里面, 15 t.start() 16 17 event_obj.clear() #设置"Flag"为Flase 18 19 inp = raw_input('input:') 20 if inp == 'true': 21 event_obj.set()
multiprocessing是要比fork更高级的库了,使用multiprocessing可以更加轻松的实现多进程程序。
#!/usr/bin/env python # -*- coding:utf-8 -*- from multiprocessing import Process import threading import time def foo(i): print 'say hi',i for i in range(10): p = Process(target=foo,args=(i,)) p.start()
注意:由于进程之间的数据需要各自持有一份,所以创建进程需要的非常大的开销。并且python不能再Windows下创建进程!
使用多进程的时候,最好是创建和和CPU核数相等的进程数?:
进程数据共享
进程各自持有一份数据,默认无法共享数据
默认的进程之间相互是独立,如果想让进程之间数据共享,就得有个特殊的数据结构,这个数据结构就可以理解为他有穿墙的功能 如果你能穿墙的话两边就都可以使用了
#!/usr/bin/env python #coding:utf-8 from multiprocessing import Process from multiprocessing import Manager import time li = [] def foo(i): li.append(i) print 'say hi',li for i in range(10): p = Process(target=foo,args=(i,)) p.start() print 'ending',li
使用特殊的数据类型,来进行穿墙:
#通过特殊的数据结构:数组(Array) from multiprocessing import Process,Array #创建一个只包含数字类型的数组(python中叫列表) #并且数组是不可变的,在C,或其他语言中,数组是不可变的,之后再python中数组(列表)是可以变得 #当然其他语言中也提供可变的数组 #在C语言中数组和字符串是一样的,如果定义一个列表,如果可以增加,那么我需要在你内存地址后面再开辟一块空间,那我给你预留多少呢? #在python中的list可能用链表来做的,我记录了你前面和后面是谁。 列表不是连续的,数组是连续的 ''' 上面不是列表是“数组"数组是不可变的,附加内容是为了更好的理解数组! ''' temp = Array('i', [11,22,33,44]) #这里的i是C语言中的数据结构,通过他来定义你要共享的内容的类型!点进去看~ def Foo(i): temp[i] = 100+i for item in temp: print i,'----->',item for i in range(2): p = Process(target=Foo,args=(i,)) p.start() 第二种方法: #方法二:manage.dict()共享数据 from multiprocessing import Process,Manager #这个特殊的数据类型Manager manage = Manager() dic = manage.dict() #这里调用的时候,使用字典,这个字典和咱们python使用方法是一样的! def Foo(i): dic[i] = 100+i print dic.values() for i in range(2): p = Process(target=Foo,args=(i,)) p.start() p.join()
1 'c': ctypes.c_char, 'u': ctypes.c_wchar, 2 'b': ctypes.c_byte, 'B': ctypes.c_ubyte, 3 'h': ctypes.c_short, 'H': ctypes.c_ushort, 4 'i': ctypes.c_int, 'I': ctypes.c_uint, 5 'l': ctypes.c_long, 'L': ctypes.c_ulong, 6 'f': ctypes.c_float, 'd': ctypes.c_double