并发编程——进程线程

并发编程

子进程回收资源的两种方式:

  1. join让主进程等待子进程结束,并回收子进程资源,主进程再结束并回收资源。
  2. 主进程‘正常结束’,子进程与主进程一并被回收资源。

守护进程:

主进程结束时,子进程也必须结束,并回收。

进程间数据是隔离的

进程互斥锁:

互斥锁是一把锁,用来保证数据读写安全的。

抢票列子

from multiprocessing import Process
from multiprocessing import Lock  # ---》 进程互斥锁
import random
import time
import json
# 抢票例子:
# 1.查看余票
def search(name):
    # 1.读取data.json文件中的数据
    with open('data.json', 'r', encoding='utf-8') as f:
        data_dic = json.load(f)
        print(f'用户【{name}】查看余票,余票还剩: {data_dic.get("number")}!')


# 2.若有余票,购买成功,票数会减少
def buy(name):  # buy()

    # 网络延时
    with open('data.json', 'r', encoding='utf-8') as f:
        data_dic = json.load(f)

    # 进入这一步证明最先抢到票
    if data_dic.get('number') > 0:
        data_dic['number'] -= 1
        time.sleep(random.randint(1, 3))
        with open('data.json', 'w', encoding='utf-8') as f:
             json.dump(data_dic, f)
        print(f'用户【{name}】, 抢票成功!')

    else:
        print(f'用户【{name}】, 抢票失败!')

def run(name, lock):
    # 1.假设1000个用户过来都可以立马查看余票
    search(name)

    lock.acquire()  # 加锁
    buy(name)
    lock.release()  # 释放锁

if __name__ == '__main__':
    lock = Lock()
    # 开启多进程: 实现并发
    for line in range(10):
        p_obj = Process(target=run, args=(f'jason{line}', lock))
        p_obj.start()

队列:

先进先出

--->[3,2,1]---->[1,2,3]

先存放的数据,就先取出来.

应用:让进程之间数据进行交互.

IPC机制(进程间实现通信)

面试会问:什么是IPC机制

from multiprocessing import Process
from multiprocessing import JoinableQueue
import time

def task1(q):
    x = 100
    q.put(x)
    print('添加数据')

    time.sleep(3)
    print(q.get())

def task2(q):
    # 想要在task2中获取task1的x
    res = q.get()
    print(f'获取的数据是{res}')
    q.put(9527)

if __name__ == '__main__':
    # 产生队列
    q = JoinableQueue(10)

    # 产生两个不同的子进程
    p1 = Process(target=task1, args=(q, ))
    p2 = Process(target=task2, args=(q, ))

    p1.start()
    p2.start()

生产者与消费者

生产者:生产数据的

消费者:使用数据的

生产油条的人总比吃油条的人少—>生产数据跟不上,使用数据的人—>供需不平衡

吃油条的人比生产的油条要少—>使用数据的速度跟不上生产数据的 速度

通过队列来实现

from multiprocessing import JoinableQueue
from multiprocessing import Process
import time

# 生产者: 生产数据 ---》 队列
def producer(name, food, q):
    msg = f'{name} 生产了 {food} 食物'
    # 生产一个食物,添加到队列中
    q.put(food)
    print(msg)

# 消费者: 使用数据 《---  列队
def customer(name, q):
    while True:
        try:
            time.sleep(0.5)
            # 若报错,则跳出循环
            food = q.get_nowait()
            msg = f'{name} 吃了 {food} 食物!'
            print(msg)
        except Exception:
            break
            
if __name__ == '__main__':
    q = JoinableQueue()

    # 创建两个生产者
    for line in range(10):
        p1 = Process(target=producer, args=('tank1', f'Pig饲料{line}', q))
        p1.start()

    # 创建两个消费者
    c1 = Process(target=customer, args=('jason', q))
    c2 = Process(target=customer, args=('sean', q))
    c1.start()
    c2.start()

线程:

什么是线程?

进程:资源单位

线程:执行单位

线程与进程都是虚拟的概念,为了更好表达某种事物.

注意:开启一个进程,一定会自带一个线程,线程才是真正的执行者.

为什么使用线程?

节省资源的占用.

开启进程:

  1. 会产生一个内存空间,申请一块资源.
  2. 会自带一个主线程
  3. 开启子进程的速度要比开启子进程的速度慢

开启线程:

  1. 一个进程内可以开启的多个线程,从进程的内存中申请执行单位.
  2. 节省资源

开启三个进程:

  1. 占用三份内存资源

开启三个线程:

  1. 从一个内存资源中,申请三个小时执行单位

IO密集型用:多线程

  1. IO(时间由用户定):

    阻塞:切换+保存状态

计算密集型用:多进程

  1. 计算(时间由操作系统定)

    计算时间很长—>切换+保存状态

注意:进程与进程之间的数据是隔离的,线程与线程之间的 数据是共享的

怎么使用线程?
from threading import Thread
import time
number = 1000

启动线程的方式一:
任务1:
def task():
    global number
    number = 100
    print('start...')
    time.sleep(1)
    print('end...')

if __name__ == '__main__':
    # 开启一个子线程
    t = Thread(target=task)
    t.start()
    # t.join()
    print('主进程(主线程)...')
    print(number)

启动线程的方式二:
class MyThread(Thread):
    def run(self):
        print('start...')
        time.sleep(1)
        print('end...')

if __name__ == '__main__':
    # 开启一个子线程
    t = MyThread()
    t.start()
    # t.join()
    print('主进程(主线程)...')

from threading import current_thread
number = 1000
def task():
    global number
    number = 100
    print(f'start...{current_thread().name}')
    time.sleep(3)
    print(f'end...{current_thread().name}')

if __name__ == '__main__':
    # 开启一个子线程
    for line in range(10):
        t = Thread(target=task)
        # 加上守护线程: 主进程结束,代表主线程也结束,子线程有可能未被回收。
        t.daemon = True
        t.start()

    # t.join()
    print(f'主进程(主线程)...{current_thread().name}')
    print(number)

线程池

线程池是用来限制 创建的线程数

线程池演示链接

posted @ 2019-12-07 19:42  Mr-Allen  阅读(104)  评论(0编辑  收藏  举报