Python8期 Day36 2019/ 6/4

Jionablequeue

1.什么是jionablequeue:创建进程队列的另外一个类(与queue相似)

2.为什么使用它:解决生产者和消费者之间平衡的问题

3.jionablequeue比queue多了task_done()与jion()两个函数

4注意:

  消费者每次从队列里面q.get()一个数据,处理过后就使用队列.task_done()(注:该函数 不是表示任务全部处理完成 而是 取出来某个数据处理完成

  生产者调用jion()进行阻塞,直到队列中所有的项目均被处理。阻塞将持续到队列中的每个项目均调用q.task_done()方法为止( task_done的次数 == put的调用次数)

5.案例

import random
import time
from multiprocessing import Process, Queue,JoinableQueue
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))
    # q.put(None)
def eat_hotdog(name,q):
    while True:
        hotdog = q.get()
        # if not hotdog:
        #     break
        time.sleep(random.randint(1, 3))
        print("%s吃掉了%s" % (name,hotdog))
        # 必须记录 该数据 处理完成了
        q.task_done()
if __name__ == '__main__':
    q = JoinableQueue()
    p = Process(target=make_hotdog,args=("owen的热狗店",q))
    p2 = Process(target=make_hotdog,args=("bgon的热狗店",q))
    p3 = Process(target=make_hotdog,args=("jerry的热狗店",q))
    c = Process(target=eat_hotdog,args=("思聪",q))
    c.daemon = True
    c2 = Process(target=eat_hotdog, args=("大葱", q))
    c2.daemon = True
    # c3 = Process(target=eat_hotdog, args=("二葱", q))
    p.start()
    p2.start()
    p3.start()
    c.start()
    c2.start()
    # c3.start()
    # 目前的思路  是当商家做完以后 放一个None  作为结束标志   不够好 必须明确商家和消费者的个数
    # 明确商家生成完毕  在明确消费者吃完了  就算结束
    p.join()
    print("第一家生成完毕")
    p2.join()
    print("第二家生成完毕")
    p3.join()
    print("第三家生成完毕")
    # 消费者吃完了
    q.join()
    print("消费吃完了!")
    print("美好的一天结束了!")

注意:要区分进程中join和joinablequeue中的join阻塞执行情况不同

 

线程

1.什么是线程:指的是CPU最小的执行单位,本质上是一堆代码构成的执行流程。

2.主线程:进程中默认的线程        子线程:程序自己开启创建的线程

3.注意:

  1)进程包含线程(进程是一个资源单位,其中存储着改程序运行的所需所有资源,可以比喻为一个车间)

  2)线程就是车间的流水线上面放的产品知错的具体方法(代码)

  3)每个进程都会有一个默认的线程

  4)每个进程可以存在多个线程

  5)创建线程的开销远比创建进程小得多

  6)线程之间没有父子关系,都是平等的()

4.开启线程的两种方法(与开启子进程相似):
from threading import Thread,current_thread
import time

def task():
    print("2",current_thread())
    print("子线程running")
    time.sleep(10)
    print("子线程over")

# 使用方法一  直接实例化Thread类
if __name__ == '__main__':
    t = Thread(target=task)
    t.start()
    
    # task()
    # 执行顺序不固定 如果开启线程速度足够快  可能子线程先执行
    print("主线程over")
    print("1",current_thread())

# 使用方法二 继承Thread 覆盖run方法
class MyThread(Thread):
    def run(self):
        print("子线程run!")
m = MyThread()
print("主线over")

# 使用方法和多进程一模一样   开启线程的代码可以放在任何位置  开启进程必须放在判断下面

 

同一个进程中多个线程共享数据

from threading import Thread
a = 10
def task():
global a
print("子 running...")
a = 20
t1 = Thread(target=task)
t1.start()
t1.join() # 主线程等待子线执行完毕
print(a) # 20

 

 

守护线程 了解

from threading import Thread
import time

def task():
    print("子1running......")
    time.sleep(100)
    print("子1over......")

def task2():
    print("子2running......")
    time.sleep(4)
    print("子2over......")
    
t = Thread(target=task)
t.daemon = True
t.start()

t2 =Thread(target=task2)
t2.start()

print("主over")

结果:

子1running......
子2running......
主over
子2over......

总结:1.守护线程会等到主线程结束立马结束,不管守护线程有没有完成任务(如果守护线程已经完成任务但主线程还没结束,守护线程立马结束)

            2.主线程会等到非守护线程结束而结束(如果主线程代码运行完了非守护线程还没结束任务,主线程会等非守护线程返回结果在结束)

线程 互斥锁

多线程可以并发执行,一旦并发了并且访问了同一个资源就会有问题

解决方案:还是互斥锁

from threading import Thread,enumerate,Lock
import time

number = 10

lock = Lock()

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

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

for t in enumerate()[1:]:
    # print(t)
    t.join()
    
print(number)   # 0

注意:线程和进程锁的使用方式不同

死锁问题

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

# 筷子
lock2 = Lock()

def eat1():
    lock1.acquire()
    print("%s抢到了盘子" % current_thread().name)
    time.sleep(0.5)
    lock2.acquire()
    print("%s抢到了筷子" % current_thread().name)

    print("%s开吃了!" % current_thread().name)
    lock2.release()
    print("%s放下筷子" % current_thread().name)

    lock1.release()
    print("%s放下盘子" % current_thread().name)


def eat2():
    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=eat1)


t2 = Thread(target=eat2)

t1.start()
t2.start()
如何避免死锁问题  
        锁不要有多个,一个足够
        如果真的发生了死锁问题,必须迫使一方先交出锁
可重入锁

Rlock 称之为递归锁或者可重入锁

Rlock不是用来解决死锁问题的

与Lock唯一的区别: Rlock同一线程可以多次执行acquire 但是执行几次acquire就应该对应release几次 如果一个线程已经执行过acquire 其他线程将无法执行acquire

from threading import RLock, Lock, Thread

# l = Lock()
#
# l.acquire()
# print("1")
# l.acquire()
# print("2")


l = RLock()

# l.acquire()
# print("1")
# l.acquire()
# print("2")

def task():
    l.acquire()
    print("子run......")
    l.release()


# 主线程锁了一次
l.acquire()
l.acquire()

l.release()
l.release()
t1 = Thread(target=task)
t1.start()

信号量 了解
Lock  RLock

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


用途: 仅用于控制并发访问   并不能防止并发修改造成的问题
"""

from threading import Semaphore, Thread
import time

s = Semaphore(5)
def task():
    s.acquire()
    print("子run")
    time.sleep(3)
    print("子over")
    s.release()

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

 

 

转载于:https://www.cnblogs.com/tfzz/p/10975608.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值