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()

<<<<<< 后续学习 >>>>>>>
原语

信号量

全部评论

相关推荐

不愿透露姓名的神秘牛友
02-14 11:10
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务