—恢复内容开始—

一:Python threading 模块

线程的创建和调用方式:

#第一种
import threading,time
def thrad_test(n):
    print('我是线程%s'%n)
    time.sleep(1)
# 格式: threading.Thread(target=函数的名字, args=(函数参数1,函数参数2))
t1 = threading.Thread(target=thrad_test, args=(1,)) # 创建线程实例1
t2 = threading.Thread(target=thrad_test, args=(2,)) # 创建线程实例2
t3 = threading.Thread(target=thrad_test, args=(3,)) # 创建线程实例3

t1.start() #启动线程
t2.start() #启动线程
t3.start() #启动线程
#第二种,继承式
import threading,time
class ThreadCust(threading.Thread):
    def __init__(self,n):
        threading.Thread.__init__(self)
        self.n = n
    def run(self):
        print('我是线程%s'%self.n)

t1 = ThreadCust(1)
t2 = ThreadCust(2)
t1.start()
t2.start()

第二:join()

import threading,time
class ThreadCust(threading.Thread):
    def __init__(self,n):
        threading.Thread.__init__(self)
        self.n = n
    def run(self):
        print('我是编号[-%s-]线程'%self.n)
        time.sleep(self.n) 
        print('我是编号[-%s-]线程, 我运行结束了'%self.n)

print('我是主线程,我开始创建子线程和运行子线程了')

t1 = ThreadCust(2)
t2 = ThreadCust(5)
t1.start() #start的作用是 主线程 启动子线程后,就扔给CPU了,不管了
t2.start()
t2.join()  
# t2线程join(),那么则表示:必须得等待t2线程执行完成,主线程才能继续往下执行,作用是用来阻塞主线程的,要join()的子线程命令主线程等待一下
print('我是主线程,但我得等待编号[-5-]的线程工作完成了,才退出')
# 加join()结果:

我是主线程,我开始创建子线程和运行子线程了
我是编号[-2-]线程
我是编号[-5-]线程
我是编号[-2-]线程, 我运行结束了
我是编号[-5-]线程, 我运行结束了

我是主线程,但是我的得等待编号[-5-]的线程工作完成了,才退出

 

 ——————————————–分割线——————————————-

# 不加join()的结果:
print('我是主线程,我开始创建子线程和运行子线程了') t1 = ThreadCust(2) t2 = ThreadCust(5) t1.start() #start的作用是 主线程 启动子线程后,就扔给CPU了,不管了 t2.start() print('我是主线程,我的工作结束了。子线程儿子们,爸爸先走了')

 

我是主线程,我开始创建子线程和运行子线程了
我是编号[-2-]线程
我是编号[-5-]线程
我是主线程,我的工作结束了。子线程儿子们,爸爸先走了
我是编号[-2-]线程, 我运行结束了
我是编号[-5-]线程, 我运行结束了

 ####由此说明:一个进程内总共有线程数量:  (一个主线程 + 创建子线程的数量) 

##小结:

一个进程内必有一个主线程,主线程的作用是执行代码(线程也是代码),创建的子线程由主线程运行后,子线程会自动的去执行它所需要执行的代码。另外,主线程从上到下的执行代码,它不管子线程运行的如何,子线程任务有没有运行完成,主线程都不管,但是如果某个子线程加了join()方法的话,那么就等于告诉主线程:主线程爸爸,你得等我执行结束了,你才能执行结束 – -!!!

 第三: setDaemon 守护线程

# setDaemon 守护线程,就是守护主线程,主线程结束,子线程也跟着结束。哪个线程设置了守护,那么哪个线程就跟主线程一起运行完毕(运行完毕,不是运行终止)
# 设置了setDamon(True)的子线程, 等于告诉主线程:主线程爸爸,你跑(运行完毕)的时候带带我 - -!!!
import threading,time
class ThreadCust(threading.Thread):
def __init__(self,n):
threading.Thread.__init__(self)
self.n = n
def run(self):
print('我是编号[-%s-]线程'%self.n)
time.sleep(self.n)
print('我是编号[-%s-]线程, 我运行结束了'%self.n)

print('我是主线程,我开始创建子线程儿子和运行子线程儿子了')
thre_list = []
t1 = ThreadCust(2)
t2 = ThreadCust(5)
thre_list.append(t1)
thre_list.append(t2)
t2.setDaemon(True) # 设置守护线程时,必须要在start()的上面设置 seDamon(True),否则有报异常
for t in thre_list:
t.start()
print('我是主线程,我的工作结束了')

#结果:

我是主线程,我开始创建子线程儿子和运行子线程儿子了
我是编号[-2-]线程
我是编号[-5-]线程
我是主线程,我的工作结束了
我是编号[-2-]线程, 我运行结束了

由结果得知:t2线程也就是编号为[-5-],任务没有完成就跟着主线程执行完毕

 第三:线程锁

#也叫互斥锁
#问题的场景:一个进程可以拥有多个线程,除主线程外,多个线程共享着进程的内存空间,
这就相当于每个线程可以访问共同的一份数据。当一个以上的线程修改同一份数据的时候,
  就会产生严重的问题

#下面的例子是多个线程修改一个全局变量
import threading,time
class ThreadCust(threading.Thread):
def __init__(self,n):
threading.Thread.__init__(self)
self.n = n
def run(self):
global var
print ('var:',var)
time.sleep(1)
var -= 1
var = 100
thre_list = []
for i in range(3): # 创建3个线程
t = ThreadCust(i)
t.start()
t.join()
print(var)
'''
# 它的正常结果应该是97,因为每个线程都执行 var - 1 操作,最后的结果可能是99、98、97等等,结果不确定性。
 这是因为多个线程创建并运行的时候,
 最先创建并运行的线程拿到的值可能是100,慢一点的线程拿到的值可能是99、98等,有非常大的不确定性。比如:
 线程1、线程2、线程3由于创建的速度和运行的速度够快,几乎同时拿到 var = 100, 这样:

  线程1的 var -= 1 那么就是 100-1=99,
  线程2的 var -= 1 那么就是 100-1=99,
  线程3的 var -= 1 那么就是 100-1=99
   最终修改可能结果:99 ,正常结果是97

 或者这样:
  可能线程1创建最快,运行最快,那么可能最先成功修改了var的值,var -= 1 此时var等于99
  线程2 和 线程3 几乎同时快,同时拿到了线程1修改后的值(99),此时:
  线程2 var -= 1 那么就是 99 - 1
  线程3 var -= 1 那么就是 99 - 1
   最终修改结果可能是98, 正常结果是97
 或者再这样:
  线程1的速度 > 线程2的速度 > 线程3的速度
  var-1=99 var-1=98 var-1=97 最终结果:97 (正确)

#注意:以上情况是属于比较理想的情况,依此类推,不理想的情况下,可能 线程1 比 线程3 的速度慢,线程2 比 线程1 的速度快
等都有这种可能,
  并不是谁最先创建谁就有执行优先权的
'''

 


----------------------------------------分割线-------------------------------------------------
解决以上的资源争夺问题:RLock,也叫递归锁
import threading,time

class ThreadCust(threading.Thread):
def __init__(self,n):
threading.Thread.__init__(self)
self.n = n
def run(self):
global var
lock.acquire() #2. 线程开始锁住,至此,其他线程不得操作变量 var,
                必须得等到 得到此锁的线程修改完毕后 其他得到锁的线程才能修改
print ('var:',var)
time.sleep(1)
var -= 1
lock.release() #3. 锁释放锁
var = 100
thre_list = []
lock = threading.RLock() #1. 生成一个锁
for i in range(3):
t = ThreadCust(i)
t.start()
t.join()
print(var) 结果:97(正确)
# 假设线程1得到锁,那么线程2、线程3则不能动,谁得到锁谁就有运行到底的优先权,所以线程2和3只能静静的看着线程1在装B - -!!!
得到锁的情况,类似如下图:~~~~~~~~~~~~~~~~~~~~

”’

Python 至始至终,同一时刻只有一个线程在工作,这是由于python 的GIL 超级大锁所决定的,它的作用就是保证同一时间只有一个线程在干活和执行权限,

哪个线程拿到GIL的执行资格,然后加了一个 RLock()锁,那么哪个线程就有执行彻底的资格,即使中途其他线程也拿到了GIL,也会处于阻塞状态并交出执行权,

一直等到RLock()的释放,其他线程才有运行的机会

”’

对比:在一个有超线程技术的双核四线程的处理器里,C++、Java可以做到一个物理核心并行两个线程,而Python始终只能运行一个线程,对CPU的极大浪费

 第四:信号量

# 有一个能容纳五个人的房间,门外有五把钥匙,谁拿到其中的一把,谁就能进去。当第六个人也想进去的时候,门口没了钥匙,他只能此时等待和排队,
  信号量也是如此,某些共享数据(比如全局变量),只能供给固定数目的线程使用
import
threading,time class ThreadCust(threading.Thread): def __init__(self,n): threading.Thread.__init__(self) self.n = n def run(self): global var s.acquire() #2. 线程开始锁住 print ('var:',var) time.sleep(1) var -= 1 s.release() #3. 线程释放锁 var = 100 thre_list = [] s = threading.Semaphore(5) # 信号量,允许五个线程去操作共享的数据 for i in range(3): t = ThreadCust(i) t.start() t.join() print(var)

 第五:Event(事件)

import threading,time
class Teacher(threading.Thread):
    def run(self):
        print('今天的作业有:')
        print('作文一篇,800字')
        print('数学题60题')
        # event状态设置为True,当前线程会被阻塞,阻塞池的其他线程将被激活处于就绪状态,等待操作系统调度
        event.set()
        time.sleep(3)
        print('开始交作业')
        event.set()

class Student(threading.Thread):
    def run(self):
        # event状态为 Flase, 则阻塞当前线程,等待 event.set() 设置为 True 后,这边的线程才能被激活
        event.wait()
        print('作业太多了,老师')
        time.sleep(3)
        # 恢复event 状态为 Flase
        event.clear()
        # 又进入 阻塞状态,等待其他线程的 event.set()
        event.wait()
        print('作业太多,做不完')
        event.clear()
thread_list = []
event = threading.Event()
tea = Teacher()
tea.start()
for i in range(3):
    stu = Student()
    stu.start()

stu.join()

小结:
# event.wait() : 如果event的状态为 Flase, 将阻塞当前线程,默认值是False
# event.set() : 设置 event 的状态为 True, 所有阻塞池的线程被激活,进入就绪状态,等待操作系统调度
# event.isSet() : 返回event的状态值
# event.clear() :  恢复event的值为False

 第6:队列queue

queue队列的方法
import queue

# 队列种类
q1 = queue.Queue(maxsize=2) # 先进先出,参数为队列的长度,不写表示队列无限大
q2 = queue.LifoQueue(maxsize=3) # 先进后出,参数为队列的长度,不写表示队列无限大
q3 = queue.PriorityQueue(maxsize=3)

# 存值
q1.put('jack') # 将值放入队列里
q1.put('tom') # 将值放入队列里

# 取值
q1.get()# 从队列取元素
print(q1.get())# 从队列取元素

# 其他方法
q1.qsize() # 返回队列大小
q1.empty() # 队列为空,返回True,否则 False
q1.full() # 队列是否已满,是,返回True, 否,返回False
q1.task_done() # 完成一项任务后,task_done() 向任务已经完成的队列发送一个信号
q1.join()  # 等到队列为空,再执行别的操作

Queue

 

import queue

q = queue.Queue()
q.put('tom')
q.put('jack')
q.put('zhangsan')

print(q.get()) # tom
print(q.get()) # jack
print(q.get()) # zhangsan

先进先出

 后进先出

 

import queue

q = queue.LifoQueue()
q.put('tom')
q.put('jack')
q.put('zhangsan')

print(q.get()) # zhangsan
print(q.get()) # jack
print(q.get()) # tom

后进先出,先进后出

import time, queue,threading,random


q = queue.Queue()
class QueueThread(threading.Thread):
    def __init__(self, name):
        super().__init__()
        self.name = name
    def run(self):
        while True:
            print('正在做包子')
            time.sleep(random.randrange(5))
            bun = random.randrange(10)
            print('大厨[-%s-]做了编号[-%s-]的包子'%(self.name, bun))
            q.put(bun) # 将包子压入队列
            q.task_done() # 向正在 q.join()的线程发送信号:现在队列里有包子了,可以取了

class Person(threading.Thread):
    def __init__(self, name):
        super().__init__()
        self.name = name
    def run(self):
        while True:
            q.join()  # 等候task_done() 的通知。有通知将执行下面代码
            bun = q.get()
            print('食客[-%s-]吃了编号[-%s-]的包子'%(self.name,bun))
            time.sleep(random.randrange(5))

qt = QueueThread('汉尼拔')
per1 = Person('威尔')
per2 = Person('史黛林')
per3 = Person('斯大林')
qt.start()
per1.start()
per2.start()
per3.start()

生产者消费者

import time, queue,threading,random
q1 = queue.Queue()
q2 = queue.Queue()
class QueueThread(threading.Thread):
    def __init__(self, name):
        super().__init__()
        self.name = name
    def run(self):
        while True:
            print('大厨[-%s-]正在等候客人点单' % self.name)
            q2.join()
            dish, guest = q2.get()
            print('大厨[-%s-]接收到客人[-%s-]点的[-%s-]' % (self.name, guest, dish))
            q1.put(dish)  # 厨师做好菜了,将菜放入q1队列
            q1.task_done() # 通知菜已经做好了,可以取了

class Person(threading.Thread):
    def __init__(self, name):
        super().__init__()
        self.name = name
    def run(self):

        while True:
            lock.acquire()
            menu = ['宫保鸡丁', '糖醋排骨', '红烧牛肉', '大肠刺身'] # 定义菜单
            dish = menu[random.randrange(4)] # 随机点菜
            time.sleep(3)
            q2.put([dish, self.name]) # 将 客人 和 菜一起压入队列
            q2.task_done()            # 通知 q2 队列,有人点菜了
            q1.join()                 # 等候厨师做菜,厨师做好后,往下执行
            dish = q1.get()           # 取菜
            print('[-%s-]点的[-%s-]菜来了' % (self.name, dish))
            if dish:
                lock.release()
                time.sleep(1)
lock = threading.RLock()
qt = QueueThread('汉尼拔')
per1 = Person('威尔')
per2 = Person('史黛林')
per3 = Person('斯大林')
qt.start()
per1.start()
per2.start()
per3.start()

个性版生产者消费者

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

—恢复内容结束—

版权声明:本文为jbzd原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/jbzd/p/9275351.html