Python--day036(JoinableeQueue、多线程)

1. JoinableQueue

from multiprocessing import JoinableQueue
# 可以被join的队列,join是等待摸个任务完成,able 可以怎么着, Queue是对垒

q = JoinableQueue()

q.put("1")
q.put("2")

print("取走了一个%s " % q.get())
q.task_done() # task_down 告诉队列这个数据已经处理完了
# 该函数不是表示任务全部处理完成,而是取出某个数据处理完成

print("再取走了%s" % q.get())
q.task_done()

print("......")
# q.join()  #等待队列中的数据处理完毕 , join, task_down的次数 == put的次数
print("Game Over")
View Code

生产者消费者问题:

生产者生产结束以后,消费者一直循环吃,吃完以后,消费者并不知道
生产者已经生产结束,就会一直等待生产者生产东西
import time
import random
from multiprocessing import JoinableQueue, Process


def make_hotdog(name, q):
    for i in range(5):
        time.sleep(random.randint(1, 3))
        print("%s生产了热狗%s" % (name, i))
        q.put("%s的%s号热狗" % (name, i))

def eat_hotdog(name, q):
    while True:
        hotdog = q.get()
        time.sleep(random.randint(1, 3))
        print("%s吃掉了%s" % (name, hotdog))
        # 每次处理完成一个数据,必须记录该数据
        q.task_done()

if __name__ == '__main__':
    q = JoinableQueue()

    p1 = Process(target=make_hotdog, args=("jerry", q))
    p2 = Process(target=make_hotdog, args=("monkey", q))
    p3 = Process(target=make_hotdog, args=("owen", q))

    c1 = Process(target=eat_hotdog, args=("思聪", q))
    c1.daemon = True
    c2 = Process(target=eat_hotdog, args=("健林", q))
    c2.daemon = True

    p1.start()
    p2.start()
    p3.start()
    c1.start()
    c2.start()

    # 明确商家生产完毕,在明确消费者吃完了,就算结束
    p1.join()
    print("第一家生产完毕")

    p2.join()
    print("第二家生产完毕")

    p3.join()
    print("第三家生产完毕")

    # 消费者吃完了
    q.join()
    print("消费者吃完了")
View Code

2. 多线程

2.1 什么是线程:

线程指的是一条流水线的工作过程的总称

线程是CPU的基本执行单位

对比进程而言,进程仅仅是一个资源单位其包含了程序运行所需的资源,就像一个车间

而单有资源是无法生产出产品的,必须有具体的生产产品的逻辑代码

线程就相当于车间中的一条流水线,而你的代码就是流水线上的一道道工序

2.2 特点:

1.每个进程都会有一个默认的线程

2.每个进程可以存在多个线程

3.同一进程中的所有线程之间数据是共享的

4.创建线程的开销远比创建进程小的多

2.3 主线程与子线程的区别:

1.线程之间是没有父子之分,是平等的

2.主线程是由操作系统自动开启的,而子线是由程序主动开启

3.即时主线程的代码执行完毕,也不会结束进程,会等待所有线程执行完毕,进程才结束

2.4 开启线程的两种方式

# 方式一 直接实例化Thread类
from threading import Thread

def task():
    print("子线程 is running")

t = Thread(target=task)
t.start()
# 执行的顺序不固定,一般来说,开启子线程的速度远远高于继续执行主线程的速度
print("主线程 is runnning")
#
# # 方式二:自定义类继承thread类
class MyThread(Thread):
    def run(self):
        print("子线程 is running")

t = MyThread()
t.start()
print("主线程 is running")
View Code

2.5 同一个进程之间数据共享

import time,os
from threading import Thread

x = 100

def task():
    global x
    x = 10
    print("线程",os.getpid())   # 与主线程的pid相同


t = Thread(target=task)
t.start()
# 主线程等待子线程执行完毕
time.sleep(3)
print(x)   # 10
print("主线程",os.getpid())
View Code

2.6 守护线程

# 守护线程
# 主线程代码结束后,不会立即结束,会等待其他所有非守护线程结束
# 守护进程会等到所有非守护线程结束后立即结束,前提是除了主线程外,还有别的非守护进程
# 当然如果守护线程已经执行完成,立马就结束了,就不会再等待其他的非守护线程

# 与守护进程的差别
# 守护进程会等到主进程结束后立即结束,虽然主进程会等待其他非守护进程的
# 子进程结束,但是守护进程不会继续等待,守护进程已经提前挂了
import time
from threading import Thread


def task1():
    print("子进程1 is running")
    time.sleep(3)
    print("子进程1 is over")

def task2():
    print("子进程2 is running")
    time.sleep(2)
    print("子进程2 is over")

t1 = Thread(target=task1)
t2 = Thread(target=task2)
t1.daemon = True
t1.start()
t2.start()
print("主进程 Game Over")
View Code

2.7 互斥锁与死锁

多线程的最主要特征之一是:同一进程中所有线程数据共享

一旦共享必然出现竞争问题。

from threading import Lock, enumerate,Thread

import time

num = 10
lock = Lock()
def task():
    global num
    lock.acquire()
    a = num
    time.sleep(0.1)
    num = a - 1
    lock.release()

for i in range(10):
    t = Thread(target=task)
    t.start()
for t in enumerate()[1:]:
    t.join()
print(num)
View Code

死锁

"""
    死锁问题
    当程序出现了不止一把锁,分别被不同的线程持有, 有一个资源要想使用必须同时具备两把锁
    这时候程序就会进程无限卡死状态 ,这就称之为死锁
    例如:
        要吃饭 必须具备盘子和筷子   但是一个人拿着盘子 等筷子  另一个人拿着筷子等盘子


    如何避免死锁问题
        锁不要有多个,一个足够
        如果真的发生了死锁问题,必须迫使一方先交出锁

"""

# 死锁案例
from threading import Thread,Lock,current_thread

# 筷子
import time

lock1 = Lock()
# 盘子
lock2 = Lock()

def task1():
    lock1.acquire()
    print("%s抢占了筷子" % current_thread().name)
    time.sleep(0.5)
    lock2.acquire()
    print("%s抢占了盘子" % current_thread().name)
    print("%s吃完了" % current_thread().name)
    lock1.release()
    print("%s放下了盘子" % current_thread().name)
    lock2.release()
    print("%s放下了筷子" % current_thread().name)


def task2():
    lock2.acquire()
    print("%s抢占了盘子" % current_thread().name)
    lock1.acquire()
    print("%s抢占了筷子" % current_thread().name)
    print("%s吃完了" % current_thread().name)
    lock1.release()
    print("%s放下了筷子" % current_thread().name)
    lock2.release()
    print("%s放下了盘子" % current_thread().name)


t1 = Thread(target=task1)

t2 = Thread(target=task2)

t1.start()
t2.start()
View Code

2.8 RLock 与 信号量

RLock

"""
    Rlock  了解
        称之为递归锁
        或者可重入锁
    Rlock不使用用来解决死锁问题的

    与Lock唯一的区别:
    Rlock同一线程可以多次执行acquire 但是执行几次acquire就应该对应release几次

    如果一个线程已经执行过acquire 其他线程将无法执行acquire

"""

from threading import Thread,RLock

rlock = RLock()

def task():
    rlock.acquire()
    print("子线程测试")


rlock.acquire()
rlock.acquire()
print("Game Over")
rlock.release()


print("123")

t = Thread(target=task)
t.start()    # Game Over
             # 123
View Code

信号量

"""
 信号量 了解
Lock  RLock

可以现在被锁定的代码 同时可以被多少线程并发访问
Lock 锁住一个马桶  同时只能有一个
Semaphore 锁住一个公共厕所    同时可以来一堆人


用途: 仅用于控制并发访问   并不能防止并发修改造成的问题
"""
from threading import Semaphore, Thread

import time

s = Semaphore(2)  # 一次可以多少个去厕所
def task():
    s.acquire()
    print("Game Start")
    time.sleep(2)
    print("Game Over")
    s.release()

for i in range(10):
    t = Thread(target=task)
    t.start()
View Code

猜你喜欢

转载自www.cnblogs.com/wangyong123/p/10974310.html