python 并发编程基础之 线程

进程互斥锁:

​ from multiprocessing import Lock

​ 让并发变成串行,牺牲了执行效率,保证了数据安全。

​ 在程序并发执行时,需要修改数据时使用。

模拟抢票实例:

data:

"ticket_num":3

代码:

import json
import time
from multiprocessing import Process
from multiprocessing import Lock


def search(user):  # 查看余票功能
    with open('data.txt', 'r', encoding='utf8') as f:  # 打开数据文件
        dic = json.load(f)
    print(f'用户{user}查看余票,还剩{dic.get("ticket_num")}张')


def buy(user):  # 余票数据修改功能
    with open('data.txt', 'r', encoding='utf8')as f:  # 再次打开是为了打开最新数据
        dic = json.load(f)  # 拿到车票相关数据

    time.sleep(0.2)   # 模拟网络延时

    if dic.get("ticket_num") > 0:  # 还有余票就购票,余票数量减1
        dic['ticket_num'] -= 1
        with open('data.txt', 'w', encoding='utf8')as f:
            json.dump(dic, f)  # 保存车票相关数据

        print(f'用户:{user}抢票成功!')
    else:
        print(f'用户:{user}抢票失败!')


def run(user, mutex):  # 抢票功能
    search(user)  # 调用查看余票功能

    mutex.acquire()  # 加锁
    buy(user)   # 抢票功能
    mutex.release()  # 解锁


if __name__ == '__main__':
    mutex = Lock()  # 调用Lock()得到一个锁对象

    for i in range(10):  # 设置10个用户来同时抢票
        # 调用Process得到一个p对象
        p = Process(target=run, args=(f'用户{i}', mutex))
        p.start()  # 创建子进程

队列:先进先出

​ 相当于内存中产生一个队列空间,可以存放多个数据,但数据的顺序是由先进的排在前面

from multiprocessing import Queue


# 调用队列类,实例化队列对象 q
q = Queue(5)  # 若传参队列中可以存放5个数据
# q1 = Queue()  # 若不传参,队列中可以存放无限大的数据,前提硬件能更得上

# put添加数据,若队列中的数据满了,则卡住
q.put(1)

# 查看队列是否满了
print(q.full())  # True

# 添加数据,若队列满了,则会报错
q.put_nowait(6)

# q.get(): 获取的数据遵循 "先进先出",若队列中无数据可取,也会卡住
print(q.get())

get_nowait:  # 获取数据,队列中若没有,则会报错
print(q.get_nowait())

# 判断队列是否为空
print(q.empty())  # False

堆栈:先进后出

ICP: 进程间通信

​ 进程间数据时相互隔离的,若想实现进程间通信,可以利用队列

from multiprocessing import Process
from multiprocessing import Queue

def test1(q):
    data = 'test1'
    q.put(data)
    print('进程1开始添加数据')

def test2(q):
    data = q.get()
    print(f'进程2开始读取数据{data}')

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

    p1 = Process(target=test1, args=(q, ))
    p2 = Process(target=test2, args=(q, ))

    p1.start()
    p2.start()

    print('主进程')

生产者和消费者:

​ 生产者生产数据,消费者使用数据

​ 程序中:通过队列,生产者把数据添加到队列中,消费者从队列中获取数据

实例:

from multiprocessing import Queue, Process
import time


def producer(name, food, q):
    for i in range(5):
        data = food, i
        msg = f'用户{name}开始制作{data}'
        print(msg)
        q.put(data)
        time.sleep(0.2)


def consumer(name, q):
    while True:
        data = q.get()
        if not data:
            break
        print(f'用户{name}开始吃{data}')


if __name__ == '__main__':

    q = Queue()

    p1 = Process(target=producer, args=('json', '油条', q))
    p2 = Process(target=producer, args=('allen', '红烧肉', q))

    c1 = Process(target=consumer, args=('jack', q))
    c2 = Process(target=consumer, args=('wills', q))

    p1.start()
    p2.start()

    c1.daemon = True
    c2.daemon = True

    c1.start()
    c2.start()

    p2.join()
    print('主进程')

线程:

什么是线程

​ 线程与进程都是虚拟单位,目的是为了更好地描述事物

​ 进程是资源单位

​ 线程是执行单位

​ 开启一个进程,一定会产生一个线程,线程才是真正的执行者

为什么要使用线程

​ 节省内存资源

​ 开启进程:

​ 1、开辟一个名称空间,每开启一个进程都会占用一份内存资源

​ 2、会自动生成一个线程

​ 开启线程:

​ 1、一个进程可以开启多个线程

​ 2、线程的开销远小于进程

​ 注意:进程可以实现并行,线程不能实现并行,线程只能实现并发,

​ 线程之间的数据是共享的

线程的两种创建方式:

方式一:

from threading import Thread
import time

def task():
    print('线程开启')
    time.sleep(1)
    print('线程结束')

if __name__ == '__main__':

    t = Thread(target=task)
    t.start()

方式二:

from threading import Thread
import time

class MyThread(Thread):
    def run(self):
        print('线程开启')
        time.sleep(1)
        print('线程结束')

if __name__ == '__main__':

    t = MyThread()
    t.start()

线程互斥锁:

from threading import Thread, Lock
mutex = Lock()
mutex.acquire()  # 上锁
······
mutex.release()  # 解锁

猜你喜欢

转载自www.cnblogs.com/allenchen168/p/11723043.html
今日推荐