Python基础-多线程(线程创建方式/线程同步/死锁问题/消息队列(Queue)/ThreadLocal)(19)

多线程

概念

线程是进程中一个“单一的连续控制流程”/执行路径

  • 线程被称为轻量级进程
  • 一个进程可以拥有多个并行的线程
  • 一个进程中的线程共享相同的内存单元/内存地址空间(可以访问相同的变量和对象),而且他们从同一个堆中分配对象(通信,数据交换,同步操作)
  • 由于线程间的通信是在同一地址空间上进行的,所以不需要额外的通信机制,这使得通信更简便并且信息传递的速度更快。

线程几种状态

多线程程序的执行顺序是不确定的,当执行到sleep时,线程将被阻塞(bloceed),到sleep结束后,线程进入就绪(runable)状态等待调度。而线程调度将自行选择一个线程执行。
Python基础-多线程(线程创建方式/线程同步/死锁问题/消息队列(Queue)/ThreadLocal)(19)_第1张图片

多线程创建方式

py中的thread模块是比较底层的模块,而threading模块是对thread模块做了一些包装,使之可以更方便的被调用。

threading模块
  • threading.enumrate(): 查看当前进程线程数量
threading.Thread类
  • 初始化参数:和多进程Process的初始化方法作用一致
  • is_alive():是否存活
  • join(): 等待创建的线程执行完
  • run():线程创建后需要执行的方法,可以被重写
  • start():启动线程
创建线程方式一:传入方法运行
import os,time,random,threading
def say(name):
    print('%sSorry'%name)
if __name__=='__main__':
    t=threading.Thread(target=say,args=('MM',))
    t.start()
    t.join()
'''
MMSorry
'''

创建线程方式二:子类化
import os,time,random,threading
class Thread_Test(threading.Thread):
    def __init__(self,name):
        #注意:初始化要放在参数赋值前面
        threading.Thread.__init__(self)
        self.name=name
    def run(self):
        print('当前进程名%s'%(self.name,))
if __name__=='__main__':
    t=Thread_Test('MM')
    t.start()
    t.join()
'''
当前进程名MM
'''

线程共享全局变量问题

  • 优点:在一个进程内的所有线程共享全局变量,能够在不适用其它方式的前提下完成多线程之间的数据共享
  • 缺点:线程对全局变量的随意改变可能造成多线程对全局变量的混乱。
共享全局变量编程:使用global关键字

当然也可以使用给方法传参的方式

import os,time,random,threading
num=100
def fun1():
    #声明num为全局变量
    global num
    for i in range(3):
        num+=1
        print(str(num),'>>>fun1')
def fun2():
    global num
    print(num,'>>>fun2')
t1=threading.Thread(target=fun1)
t1.start()
time.sleep(1)
t2=threading.Thread(target=fun2)
t2.start()
'''
通过结果可以看出,两个线程共享num变量
101 >>>fun1
102 >>>fun1
103 >>>fun1
103 >>>fun2
'''
ThreadLocal变量
  • 一个ThreadLocal变量虽然是全局变量,但是每个线程都只能读写自己线程的独立副本。这样就解决了参数在一个线程中各个参数之间的传递问题。
  • ThreadLocal最常用的操作就是为每一个线程绑定一个数据库连接,HTTP请求,用户身份信息等,这样一个线程的所有调用函数都可以方便的访问资源。
import os,time,random,threading
def fun1(name):
    local.name=name
    fun2()
def fun2():
    name=local.name
    print(name)

#创建全局的ThreadLocal对象
local=threading.local()
for i in range(5):
    threading.Thread(target=fun1,args=(i,)).start()

线程同步问题(加锁)

概念
  • 多个线程几乎在同时修改某一共享数据时,需要进行同步控制
  • 线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制就是引入互斥锁
  • 互斥锁保证每次只有一个线程能够进程写操作,从而保证数据的准确性
  • threading模块定义了lock类来进行锁操作
lock类
  • Lock():创建锁
  • acquire([blocking]): 进入同步状态,如果blocking为True,则当前线程会阻塞,直到获取锁,False则不会阻塞。默认为True。
  • release():释放锁
同步编程
import os,time,random,threading
num=100
def fun1():
    #声明num为全局变量
    global num
    #获取锁
    lock.acquire()
    try:
        for i in range(100):
            num += 1
            print(str(num), '>>>fun1')
    finally:
        #释放锁
        lock.release()

def fun2():
    global num
    lock.acquire()
    try:
        for i in range(100):
            num += 1
            print(str(num), '>>>fun2')
    finally:
        lock.release()
lock=threading.Lock()
t1=threading.Thread(target=fun1)
t1.start()
time.sleep(1)
t2=threading.Thread(target=fun2)
t2.start()

死锁问题

线程间共享多个资源时,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会进入死锁状态。

import os,time,random,threading
num=100
def fun1():
    #声明num为全局变量
    global num
    #获取锁
    lock1.acquire()
    try:
        print('>>>fun1')
        time.sleep(1)
        lock2.acquire()
        for i in range(100):
            num += 1
            print(str(num), '>>>fun1')
        lock2.release()
    finally:
        #释放锁
        lock1.release()

def fun2():
    global num
    lock2.acquire()
    print('>>>fun2')
    time.sleep(1)
    try:
        lock1.acquire()
        for i in range(100):
            num += 1
            print(str(num), '>>>fun2')
        lock1.release()
    finally:
        lock2.release()
lock1=threading.Lock()
lock2=threading.Lock()
t1=threading.Thread(target=fun1)
t2=threading.Thread(target=fun2)
t1.start()
t2.start()
'''
>>>fun1
>>>fun2
'''

线程间消息队列

py的Queue模块提供了同步的,线程安全的队列类

  • FIFO(先进先出):Queue
  • LIFO(先进后出): LifoQueue ,栈模式
  • 优先级队列:PriorityQueue

这些队列都是实现了锁原语(原子操作),可以在多线程中直接使用。

生产者消费者

from queue import Queue,LifoQueue,PriorityQueue
import os,time,random,threading
class Producer(threading.Thread):
    global queue
    def run(self):
        count=0
        while True:
            if queue.qsize()<1000:
                count+=1
                msg='生产者'+str(count)
                queue.put(msg)
                print(msg)
class Consumer(threading.Thread):
    def run(self):
        global queue
        while True:
            if queue.qsize()>0:
                msg=self.name+'消费了'+queue.get()
                print(msg)

#queue=Queue()
queue=PriorityQueue()
#queue=LifoQueue()
for i in range(5):
    Producer().start()
for i in range(5):
    Consumer().start()

你可能感兴趣的:(Python基础)