美文网首页
多线程&python(note实战笔记)

多线程&python(note实战笔记)

作者: Luy_ | 来源:发表于2020-10-13 21:36 被阅读0次

一.理论知识

What is 进程

  • 进程是执行中的程序
  • 拥有独立地址空间、内存、数据栈等操作系统管理
  • 派生(fork或spawn)新进程
  • 进程问通信(IPC)方式共享信息

什么是线程

  • 同进程下执行,并共享相同的上下文。
  • 线程间的信息共享和通信更加容易
  • 多线程并发执行

So,Python与线程是什么关系

  • 解释器主循环
  • 主循环中只有一个控制线程在执行
  • 使用全局解释器锁(GIL)

GIL!?

GIL保证一个线程

  • 设置GIL
  • 执行下面操作之一
    • 指定数量的字节码指令
    • 线程主动让出控制权
  • 心切换进一个线程去运行
  • 把线程设置回睡眠状态(切换出线程)
  • 解锁GIL
  • 重复上面的步骤

二.实战

python的两种线程管理

  • _thread:提供了基本的线程和锁
  • threading:提供了更高级别,功能更全的线程管理(**推荐使用,基于_thread)
    • 支持同步机制
    • 支持守护线程

实战笔记

  • 1._thread的使用
from time import sleep, ctime

import logging
import _thread
'''
@author: Luy
@data:2020-10-12 13:15
@Summary:_thread的使用与理解

'''
#设置日志级别。
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)的原因
    #_thread当主线程退出之后,所有的子线程都会被kill掉(没有守护线程的概念)
    sleep(6)
    logging.info("end all at " + ctime())

if __name__ == '__main__':
    main()

*_thread不守护线程,当主线程退出之后,所有的子线程都会被kill掉,所以需要加sleep来进行等待,确保子进程顺利执行

  • 2.如何使用_thread加锁
    • 在1中,两个子线程只能通过等待来确保执行,这样效率太低了,
    • 在thread中,可以通过加锁来监视两个子线程是不是执行完了,如果执行完了主线程再退出
'''
@author: Luy
@data:2020-10-12 13:15
@Summary:_thread的锁操作

'''

from time import sleep, ctime

import logging
import _thread

logging.basicConfig(level=logging.INFO)

loops = [2, 4]

'''
nloop-用于标识当前loop属于第几个
nsec-时间,告诉我们这个循环了多长的时间
lock-传进来的锁,首先,会传进来一个锁住的锁,当我们loop执行结束后子线程都会进行解锁,当判断到所有的线程都解锁了,此时主进程就可以结束了
'''
def loop(nloop, nsec, lock):
    logging.info("start loops" + str(nloop) + " at " + ctime())
    #传一个动态时间
    sleep(nsec)
    logging.info("end loops " + str(nloop) + "at " + ctime())
    #对锁进行一个释放
    lock.release()


def main():

    logging.info("start all at " + ctime())
    #声明一个锁的list
    locks = []
    nloops = range(len(loops))

    for i in nloops:
        #取出之后我们声明一个新的锁lock
        lock = _thread.allocate_lock()
        #上锁
        lock.acquire()
        #加锁之后传递给locks
        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()

使用threading实现上面的内容

from time import sleep, ctime

import logging
import _thread
import threading

logging.basicConfig(level=logging.INFO)

loops = [2, 4]


def loop(nloop, nsec):
    logging.info("start loops" + str(nloop) + " at " + ctime())
    sleep(nsec)
    logging.info("end loops " + str(nloop) + "at " + ctime())

def main():


    logging.info("start all at " + ctime())
    threads = []
    nloops = range(len(loops))


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

    logging.info("end all at " + ctime())


if __name__ == '__main__':
    main()

面向对象的多线程写法

  • 使用一个class继承threading,然后再调用init的方法,主动调用之后,再重写run方法,
from time import sleep, ctime

import logging
import _thread
import threading


##面向对象的写法
#原语
##锁
##信号量
##

logging.basicConfig(level=logging.INFO)

loops = [2, 4]

#创建一个类继承threading的Thread方法,
class MyThread(threading.Thread):
    #1.主动调用Thread的初始构造方法,把其他传进来的参数,存到类中
    def __init__(self, func, args, name=''):
        threading.Thread.__init__(self)
        self.func =func
        self.args = args
        self.name =name
    #2.重写方法
    def run(self):
        self.func(*self.args)


def loop(nloop, nsec):
    logging.info("start loops" + str(nloop) + " at " + ctime())
    sleep(nsec)
    logging.info("end loops " + str(nloop) + "at " + ctime())

def main():

    logging.info("start all at " + ctime())
    threads = []
    nloops = range(len(loops))


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

    logging.info("end all at " + ctime())


if __name__ == '__main__':
    main()

相关文章

网友评论

      本文标题:多线程&python(note实战笔记)

      本文链接:https://www.haomeiwen.com/subject/mtjvpktx.html