Python多线程
什么是进程?
- 进程是执行中的程序
- 拥有独立地址空间、内存、数据栈等
- 操作系统管理
- 派生(fork或spawn)新进程
- 进程间通信(IPC)方式共享信息
什么是线程?
- 同进程下执行,并共享相同的上下文
- 线程间的信息共享和通信更加容易
- 多线程并发执行
- 需要同步原语
Python与线程
- 解释器主循环
- 主循环中只有一个控制线程在执行
- 使用全局解释器锁(GIL) ——同步原语技术
GIL保证一个线程
- 设置GIL
- 切换进一个线程去运行
- 执行下面操作之一
- 指定数量的字节码指令
- 线程主动让出控制权
- 把线程设置回睡眠状态(切换出线程)
- 解锁GIL
- 重复上述步骤
Python提供两种线程管理
- _thread:提供了基本的线程和锁
- threading:提供了更高级别、功能更全面的线程管理
- 支持同步机制
- 支持守护线程
例1._thread初识
import _thread import logging from time import sleep, ctime logging.basicConfig(level=logging.INFO) def loop0(): logging.info("start loop0 at " + ctime()) sleep(4) logging.info("end loop0 at " + ctime()) def loop1(): logging.info("start loop1 at " + ctime()) sleep(2) logging.info("end loop1 at " + ctime()) def main(): logging.info("start all at " + ctime()) _thread.start_new_thread(loop0,()) _thread.start_new_thread(loop1,()) sleep(6) logging.info("end all at " + ctime()) if __name__ == '__main__': main()
打印结果:
说明
如果不加_thread,那么两个循环loop会依次执行,loop0等待4秒后,loop1接着等待2秒;
而加入_thread后,两个loop相当于两个线程,可以进行并行运行(同时开始);
那为什么要在main中加个sleep(6)等待6秒呢,因为_thread有个不成文的规定:当主进行停止后,会把所有的子进程自动杀死
那可不可以不等待,而是判断子进程有没有全部结束呢?可以的,可以利用锁进行
为什么第二个循环不跟在第一个循环里面?因为获取锁的过程是需要时间的,避免第一个进程以及执行完了而第二个锁还没有获取好的情况
- _thread改进(加入锁)
import _thread import logging from time import sleep, ctime logging.basicConfig(level=logging.INFO) loops=[2,4] def loop(nloop, nsec, lock): logging.info("start loop" + str(nloop) + "at " + ctime()) sleep(nsec) logging.info("end loop" + str(nloop) + "at " + ctime()) lock.release() #释放锁 def main(): logging.info("start all at " + ctime()) locks=[] nloops = range(len(loops)) for i in nloops: lock = _thread.allocate_lock() lock.acquire() #加锁 locks.append(lock) for i in nloops: #开启线程 _thread.start_new_thread(loop, (i,loops[i], locks[i])) for i in nloops: while locks[i].locked(): pass #判断有没有解锁 logging.info("end all at " + ctime()) if __name__ == '__main__': main()
例2 :使用更高级的threading
import logging import threading from time import sleep, ctime logging.basicConfig(level=logging.INFO) loops=[2,4] def loop(nloop, nsec): logging.info("start loop" + str(nloop) + "at " + ctime()) sleep(nsec) logging.info("end loop" + str(nloop) + "at " + ctime()) def main(): logging.info("start all at " + ctime()) nloops = range(len(loops)) threads=[] for i in nloops: #开启线程 t = threading.Thread(target=loop, args=(i,loops[i])) threads.append(t) for i in nloops: threads[i].start() for i in nloops: threads[i].join() #join是threading自带的方法,可以判断每个进程是否执行完(如果没有执行完就会阻塞) logging.info("end all at " + ctime()) if __name__ == '__main__': main()
推荐使用:自己定义一个类,继承Thread方法,并对run进行改写,自己进行线程的管理
import logging import threading from time import sleep, ctime logging.basicConfig(level=logging.INFO) loops=[2,4] class MyThread(threading.Thread): def __init__(self,func,args,name=''): #继承Thread的初始 threading.Thread.__init__(self) self.func = func self.args = args self.name = name def run(self): #重写run函数 self.func(*self.args) def loop(nloop, nsec): logging.info("start loop" + str(nloop) + "at " + ctime()) sleep(nsec) logging.info("end loop" + str(nloop) + "at " + ctime()) def main(): logging.info("start all at " + ctime()) nloops = range(len(loops)) threads=[] for i in nloops: #开启线程 t = MyThread(loop, (i,loops[i]), loop.__name__) threads.append(t) for i in nloops: threads[i].start() for i in nloops: threads[i].join() #join是threads自带的方法,可以判断每个进程是否执行完(如果没有执行完就会阻塞) logging.info("end all at " + ctime()) if __name__ == '__main__': main()
<<<<<< 后续学习 >>>>>>>
原语
锁
信号量