并发编程3

内置队列

from multiprocessing import Queue


q = Queue(5)  # 自定义队列的长度
# put方法向队列中存放数据
q.put(111)
q.put(222)
q.put(333)
q.put(444)
print(q.full())  # False,full()用于判断队列是否已满
q.put(555)
print(q.full())  # True
# q.put(666)  # 超出最大长度会原地等待队列出现空位
print(q.get())
print(q.get())
print(q.get())
print(q.get())
print(q.empty())  # False,empty()判断队列是否为空
# print(q.get())
print(q.empty())  # True
# print(q.get())  # 队列中没有值,会阻塞等待
print(q.get_nowait())  # 555,队列中如果没有值会报错

IPC机制

from multiprocessing import Process, Queue


def producer(q):
    q.put('子进程producer往队列中添加值')


def consumer(q):
    print('子进程consumer从队列中取值>>>:', q.get())


if __name__ == '__main__':
    q = Queue()
    p = Process(target=producer, args=(q,))
    p1 = Process(target=consumer, args=(q,))
    p.start()
    p1.start()
    q.put(999)  # 主进程往队列中存放数据999
    # print(q.get())
    print('主进程')

生产者消费者模型

from multiprocessing import Process, Queue
import time
import random


def producer(name, food, q):
    for i in range(1, 6):
        data = f'{name}上架了{food}{i}'
        print(data)
        time.sleep(random.randint(1, 3))  # 模拟产生过程
        q.put(data)


def consumer(name, q):
    while True:
        food = q.get()
        time.sleep(random.random())
        print(f'{name}购买了{food}')


if __name__ == '__main__':
    q = Queue()
    p1 = Process(target=producer, args=('tmall', '康师傅老坛酸菜面', q))
    p2 = Process(target=producer, args=('jd', '统一老坛酸菜面', q))
    c1 = Process(target=consumer, args=('杰杰', q))
    c2 = Process(target=consumer, args=('多多', q))
    c1.daemon = True
    c2.daemon = True
    p1.start()
    p2.start()
    c1.start()
    c2.start()
    p1.join()
    p2.join()
    q.put(None)  # 结束信号的个数要跟消费者个数一致
    q.put(None)
    print('主线程')
from multiprocessing import Process, JoinableQueue
import time
import random


def producer(name, food, q):
    for i in range(1, 6):
        data = f'{name}上架了{food}{i}'
        print(data)
        time.sleep(random.randint(1, 3))  # 模拟产生过程
        q.put(data)


def consumer(name, q):
    while True:
        food = q.get()
        time.sleep(random.random())
        print(f'{name}购买了{food}')
        q.task_done()  # 每次拿数据必须给队列一个反馈


if __name__ == '__main__':
    q = JoinableQueue()
    p1 = Process(target=producer, args=('tmall', '康师傅老坛酸菜面', q))
    p2 = Process(target=producer, args=('jd', '统一老坛酸菜面', q))
    c1 = Process(target=consumer, args=('杰杰', q))
    c2 = Process(target=consumer, args=('多多', q))
    c1.daemon = True
    c2.daemon = True
    p1.start()
    p2.start()
    c1.start()
    c2.start()
    p1.join()
    p2.join()
    q.join()  # 等待队列中数据全部取出
    print('主线程')

线程理论

什么是线程

进程:资源单位
线程:执行单位
进程相当于车间,线程相当于车间里面的流水线,一个进程中至少有一个线程

为什么要有线程

开设线程的消耗远远小于进程
开进程

  1. 申请内存空间
  2. 拷贝代码
    开线程
    一个进程内可以开设多个线程,无需申请内存空间和拷贝代码
    一个进程内的多个线程数据是共享的

开设线程的两种方式

# 方式一
from threading import Thread
import time


def task(name):
    print(f'{name} is running')
    time.sleep(2)
    print(f'{name} is over')


if __name__ == '__main__':
    t = Thread(target=task, args=('mi_chat',))
    t.start()
    print('主线程')
# 方式二
from threading import Thread
import time


class MyThread(Thread):
    def __init__(self, thread_name):
        super().__init__()
        self.thread_name = thread_name
    def run(self):
        print(f'{self.thread_name} jason is running')
        time.sleep(2)
        print(f'{self.thread_name} is over')


if __name__ == '__main__':
    t = MyThread('Net_ease_music')
    t.start()
    print('主线程')

线程实现TCP服务端并发

# 客户端
import socket


client = socket.socket()
client.connect(('127.0.0.1', 8088))


while True:
    send_msg = input('请输入发送的消息>>>:').strip()
    client.send(send_msg.encode('utf8'))
    data = client.recv(1024)
    print(data.decode('utf8'))
# 服务端
import socket
from threading import Thread

server = socket.socket()
server.bind(('127.0.0.1', 8088))
server.listen()


def talk(sock):
    while True:
        data = sock.recv(1024)
        print(data.decode('utf8'))
        sock.send(data.upper())


while True:
    sock, addr = server.accept()
    t = Thread(target=talk, args=(sock,))
    t.start()

线程join方法

from threading import Thread
import time


def task(thread_name):
    print(f'{thread_name} is running')
    time.sleep(2)
    print(f'{thread_name} is over')


t = Thread(target=task, args=('youtube_shorts', ))
t.start()
t.join()
print('主线程')

线程间数据共享

from threading import Thread

nationality = 'China'


def task():
    global nationality
    nationality = 'UK'


t = Thread(target=task)
t.start()
t.join()
print(nationality)

线程对象属性和方法

验证一个进程下的多个线程是否真的处于一个进程

from threading import Thread, active_count, current_thread
import os
import time
def task():
    time.sleep(1)
    print('子线程获取进程号>>>:', os.getpid())


t = Thread(target=task)
t1 = Thread(target=task)
t.start()
t1.start()
print('主线程获取进程号>>>:', os.getpid())

统计进程下活跃的线程数

active_count()

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


def task():
    time.sleep(1)
    print('子线程获取进程号>>>:', os.getpid())


t = Thread(target=task)
t1 = Thread(target=task)
t.start()
t1.start()
print(active_count())

获取线程的名字

from threading import Thread, current_thread
import os
import time


def task():
    time.sleep(1)
    print('子线程获取进程号>>>:', os.getpid())
    print(current_thread().name)


t = Thread(target=task)
t1 = Thread(target=task)
t.start()
t1.start()
print(current_thread().name)

守护线程

主线程要等待所有非守护线程结束才可以结束

from threading import Thread
import time


def task(thread_name):
    print(f'{thread_name} is running')
    time.sleep(2)
    print(f'{thread_name} is over')


if __name__ == '__main__':
    t1 = Thread(target=task, args=('qq_zone',))
    t2 = Thread(target=task, args=('qq_show',))
    t1.daemon = True
    t1.start()
    t2.start()
    print('主线程')

GIL全局解释器锁

GIL全局解释器锁只存在于CPython解释器,不是python的特征
GIL是一把用于阻止同一个进程下的多个线程同时执行的互斥锁
存在的原因是CPython解释器中的垃圾回收机制不是线程安全的
反向验证GIL的存在是必要的,如果不存在会产生垃圾回收机制与正常线程之间数据错乱
GIL是加在CPython解释器上的互斥锁,同一个进程下的多个线程要执行必须先抢GIL锁
GIL全局解释器锁的存在让同一个进程下多个线程肯定不能同时运行,无法发挥多核优势

posted @ 2022-04-20 21:48  一梦便是数千载  阅读(19)  评论(0编辑  收藏  举报