共享内存(IPC进程间通信) 生产者消费者模型 线程理论 开启线程Thread 线程的相关对象与方法 守护线程 互斥锁

共享内存(IPC进程间通信)
1.管道
一个进程写,一个进程读的情况,两个进程涉及不到数据安全的问题可以用管道来实现共享内存

2.队列(管道+锁)
队列使用于本地,不能基于网络通信

# 队列代码实现
from multiprocessing import Queue

q = Queue(3)  # 列表里面存的值跟取的值都是放入q里面的,Queue(3)表示队列里面最多只能放3个值,如果超过3个值,那么该队列则处于堵塞状态

队列里面放值
q.put([1, 2, 3])
q.put({"a": 1})
q.put("xxxx")
q.put(100000)
q.put(1000, block=True, timeout=3)  # block=True,可以通过timeout来指定超时时间,队列满了,超时会直接抛出异常
q.put(1000, block=False)     # block=False,队列满了就直接抛出异常

队列里面取值
print(q.get())
print(q.get())
print(q.get())
print(q.get(block=False))   # block=False,取不到值就直接抛出异常
print(q.get(block=True, timeout=3))  # block=True,可以通过timeout来指定超时时间,取不到值的情况下,超时会直接抛出异常

生产者消费者模型
什么是生产者消费者模型:
该模型有两种角色:一种是生产者,另外一种是消费者
生产者负责产生数据,消费者负责取走数据进行处理

生产者与消费者通过队列通信

优点:解耦合,平衡了生成者的生产力与消费者的处理能力

生产者与消费者模型案例
方式1()
from multiprocessing import Process, Queue
import time
import random


def producer(q, name, food):
    for i in range(3):
        res = "%s %s" % (food, i)
        time.sleep(random.randint(1, 3))
        q.put(res)
        print("%s 生成了 %s" % (name, res))


def consumer(q, name):
    while True:
        res = q.get()
        if res is None:
            break
        time.sleep(random.randint(1, 3))
        print("%s 吃了 %s" % (name, res))


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

    p1 = Process(target=producer, args=(q, "厨师1", "包子"))
    p2 = Process(target=producer, args=(q, "厨师2", "烧卖"))
    p3 = Process(target=producer, args=(q, "厨师3", "面条"))

    c1 = Process(target=consumer, args=(q, "吃货1"))
    c2 = Process(target=consumer, args=(q, "吃货2"))

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

    p1.join()
    p2.join()
    p3.join()
    q.put(None)
    q.put(None)
    print("主进程")
逻辑:先造产品,造好产品后,再运行主进程,主进程再增加两个None,按照队列依次取值的特性,最后两次取值只能取到None。
方式2
from multiprocessing import Process, JoinableQueue
import time
import random


def producer(q, name, food):
    for i in range(3):
        res = "%s %s" % (food, i)
        time.sleep(random.randint(1, 3))
        q.put(res)
        print("%s 生成了 %s" % (name, res))
    q.join()  # 等队列的值都被取干净了,再结束


def consumer(q, name):
    while True:
        res = q.get()
        time.sleep(random.randint(1, 3))
        print("%s 吃了 %s" % (name, res))
        q.task_done()  # 每次执行一次取值都会发送一次信号


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

    p1 = Process(target=producer, args=(q, "厨师1", "包子"))
    p2 = Process(target=producer, args=(q, "厨师2", "烧卖"))
    p3 = Process(target=producer, args=(q, "厨师3", "面条"))

    c1 = Process(target=consumer, args=(q, "吃货1"))
    c2 = Process(target=consumer, args=(q, "吃货2"))
    c1.daemon = True
    c2.daemon = True

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

    p1.join()
    p2.join()
    p3.join()
    print("主进程")

线程理论

线程:一条流水线的运行过程(进程里面代码运行的过程就叫线程,与资源无关)

线程是一个执行单位,cup执行的就是线程
进程是一个资源单位
同一进程下的多个线程,共享进程资源;不同进程下的线程是不可以共享资源的

线程与进程的关系与差别
1.同一个进程下的多个线程共享该进程的内存资源
2.开启子线程的开销要远远小于开启子进程

用户空间线程与内核空间线程
用户空间线程:用户级线程内核的切换由用户态程序自己控制内核切换,
不需要内核干涉,少了进出内核态的消耗,但不能很好的利用多核cpu。
内核空间线程:切换由内核控制,当线程进行切换的时候,由用户态
转化为内核态。切换完毕要从内核态返回用户态。

python属于内核空间线程,由cup控制

开启线程的两种方式

开启进程的方式1
进程的特性1:开启子线程的开销要远远小于开启子进程
from threading import Thread, current_thread  # current_thread


def task():
    print("%s is running" % current_thread().name)   # 先打印这一行,pid是一样的
    # current_thread().name 会获得当前线程的名字


if __name__ == '__main__':
    t = Thread(target=task)
    t.start()
    print("主线程", current_thread().name)   # 再打印这一行,pid是一样的
    # current_thread().name 会获得当前线程的名字
进程的特性2:同一个进程下的多个线程共享该进程的内存资源
from threading import Thread

n = 100
def task():
    global n
    n = 0


if __name__ == '__main__':
    t = Thread(target=task)
    t.start()
    t.join()
    print("主线程", n)
开启进程的方式2
from threading import Thread


class Mythread(Thread):
    def __init__(self, name):
        super().__init__()
        self.name = name

    def run(self) -> None:
        print("%s is running" % self.name)


if __name__ == '__main__':
    t = Mythread("线程1")
    t.start()

线程相关对象与方法

from threading import Thread, current_thread, active_count,enumerate
import time


def task():
    print("%s is running" % current_thread().name)
    time.sleep(5)


if __name__ == '__main__':
    t = Thread(target=task)
    t.start()
    print(t.is_alive())  # is_alive()判断线程是否存活
    print(active_count())  # 查看活着的线程数
    print(enumerate())  # 显示了一个列表,里面是线程对象

守护线程(了解)

守护进程守护的是主进程的运行时间,守护线程守护的是主进程的生命周期
线程跟进程一样,主线程也是需要等子线程运行结束后,主线程才会结束
守护进程跟守护线程一样,都不能开启子进程或者子线程

from threading import Thread, current_thread, active_count
import os
import time


def task(n):
    print("%s is run" % current_thread().name)
    time.sleep(n)
    print("%s is end" % current_thread().name)


if __name__ == '__main__':
    t1 = Thread(target=task, args=(3,))
    t2 = Thread(target=task, args=(5,))
    t3 = Thread(target=task, args=(100,))
    t3.daemon = True

    t1.start()
    t2.start()
    t3.start()
    print("主")

互斥锁

降低数据运行的效率,保护了数据安全。

from threading import Thread, Lock
import time

n = 100
mutex = Lock()


def task():
    global n
    with mutex:
        teep = n
        time.sleep(0.1)
        n = teep - 1


if __name__ == '__main__':
    thread_l = []
    start_time = time.time()
    for i in range(100):
        t = Thread(target=task)   
        thread_l.append(t)		# 把每一次运行的线程对象添加到列表里面(并发)
        t.start()

    for obj in thread_l:
        obj.join()		# 把线程对象依次加上join,这样一个线程抢到锁运行完后,下一次其他线程才能抢锁运行

    print("主", n, time.time() - start_time)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值