并发编程总体课程1

多道技术
    多道技术中的多道指的是多个程序,多道技术的实现是为了解决多个程序竞争或者说共享同一个资源(如cpu)的有序调度问题,解决方式即多路复用,多路复用分为时间上的复用和空间上的复用
    空间上的复用:将内存分为几部分,每一个部分放一个程序,这样,同一时间内存中就由了多道程序

    时间上的复用:当一个程序在等待io时,另一个程序可以使用CPU,如果内存中可以同时存放足够多的作业,则cpu的利用率可以接近100%,类似于小学所学的统筹方法.
    操作系统采用了多道技术后,可以控制进程的切换,或者说进程之间去争抢cpu的执行权限,这种切换不仅会在一个进程遇到io时进行,一个进程占用cpu时间过长也会被切换,或者说被操作系统夺走cpu的执行权限.

进程调度:
    1.先来先服务 FCFS
    2.短作业优先
    3.时间片轮转
    4.多级反馈队列

进程的三种状态:就绪,阻塞,运行

同步异步,阻塞非阻塞
    同步就是当一个进程发起一个函数(任务)调用的时候,一直等到函数(任务)完成,而程序继续处于激活状态.而异步情况下是当一个进程发起一个函数(任务)调用的时候,不会等函数返回,而是继续往下执行代码,函数返回的时候通过状态,通知,事件等方式通知进程任务完成
    阻塞非阻塞是针对进程或线程,阻塞是当请求不能满足的时候就将进程挂起(如遇到io),而非阻塞则不会阻塞当前进程.

创建进程的两种方式:
# 第一种:先定义函数,后调用multiprocessing模块创建子进程
# from multiprocessing import Process
# import time
#
#
# def task(n):
#     print('我是子进程')
#     time.sleep(n)
#     print('子进程结束')
#
#
# if __name__ == '__main__':
#     # args=(), kwargs={}
#     # t=Process(task,args=(1,))
#     t = Process(target=task, kwargs={'n': 1})
#     t.start()  # 通知操作系统,开启进程,执行task函数
#     print('主')

# 第二种:调用multiprocessing模块,创建类,继承Process,注意:__init__方法中,先继承父类的__init__方法,这样实例化的时候结果就是进程,后面调用的时候不是调用run,还是start()

# from multiprocessing import Process
# import time
#
# class Task(Process):
#     def __init__(self, n):
#         super().__init__()
#         self.n = n
#
#     def run(self):
#         print('我是子进程')
#         time.sleep(self.n)
#         print('子进程结束')
#
#
# if __name__ == '__main__':
#     t = Task(1)
#     # t.run(1)  # 不是调用t.run(),而是调用t.start()
#     t.start()
#     print('主')

join方法:等待子进程执行完成
    PS:t.join() 可控制子进程执行完毕后才继续执行下面代码

进程间数据相互隔离:
    建立的子进程中的数据变更,与主进程中的数据无关,两者隔离没有关系

进程对象及其他方法
    1.windows: tasklist |findstr 进程的id号
    2.mac,linux: ps aux | grep 进程id号
    3.进程对象: t = Process(target = task,) 或者在进程内部 current_process()
    4.t.pid或者 current_process().pid 获取进程id号
    5.os.getpid()同上,获取进程的id号
    6.os.getppid()获取父进程的id号,子进程中获取父进程id,等于父进程的id号
    7.t.is_alive()或者current_process().is_alive() 查看进程是否存活
    8.t.terminate()关闭进程,在主进程关闭  PS:异步操作,不是立即关闭的,需要时间

僵尸进程与孤儿进程
    僵尸进程:进程结束了,但是资源还没来得及回收
    孤儿进程:主进程挂了,子进程还没结束,他就会被专门的进程接管

守护进程
    定义:一旦主进程结束,子进程也结束
    语法:t.daemon = True 一定要加在启动start之前
# from multiprocessing import Process,current_process
# import time
# import os
# 
# def task():
#     print(os.getpid())
#     print('子进程')
#     time.sleep(200)
#     print('子进程结束')
# 
# 
# if __name__ == '__main__':
#     t = Process(target=task, )
#     # 守护进程:主进程一旦结束,子进程也结束
#     t.daemon=True  # 一定要加在启动之前
#     t.start()
# 
# 
#     time.sleep(1)
#     print('主进程结束')

互斥锁:同时只有一个人能拿到,必须释放,其他人才能再次获取到,并行改串行

# from multiprocessing import Process, Lock
# import json
# import time
# import random
# 
# 
# def search():
#     # 查票的函数
#     # 打开文件,读出ticket_count
#     with open('ticket.json', 'r', encoding='utf-8') as f:
#         dic = json.load(f)
#         print('余票还有:', dic.get('ticket_count'))
# 
# 
# def buy():
#     with open('ticket.json', 'r', encoding='utf-8') as f:
#         dic = json.load(f)
# 
#     time.sleep(random.randint(1, 3))  # 模拟一下网络延迟
#     if dic.get('ticket_count') > 0:
#         # 能够买票
#         dic['ticket_count'] -= 1
#         # 保存到文件中去
#         with open('ticket.json', 'w', encoding='utf-8') as f:
#             json.dump(dic, f)
#             print('买票成功')
#     else:
#         # 买票失败
#         print('买票失败')
# 
# 
# # 写一个函数,先查票,再买票
# 
# def task(mutex):
#     search()
#     # 买票过程要加锁
#     # 买前加锁
#     # mutex.acquire()
#     # buy()  # 10个进程变成了串行执行
#     # # 买后释放锁
#     # mutex.release()
#     with mutex:
#         buy()
# 
# 
# if __name__ == '__main__':
#     # 锁的创建,在哪?主进程创建锁
#     mutex = Lock()  # 创建一把锁
#     # 模拟十个人买票(开10个进程)
#     for i in range(10):
#         t = Process(target=task, args=(mutex,))
#         t.start()


PS:分析:查票和买票的函数比较简单,创建函数task,将查票和买票放到一起,其中需要加上互斥锁的只有买票环节,主进程先创建一把锁:mutex = Lock(),在task函数中,买前先加锁,mutex.acquire(),买完后释放锁 mutex.release(),可用上下文管理 with 来替代,with mutex
创建10个子进程,用for i in range(10)来就可以

队列

# from multiprocessing import Queue
# 
# 
# # 实例化得到要给对象
# 
# q=Queue(5)  # 默认很大,可以放很多,写了个5,只能放5个
# 
# # 往管道中放值
# q.put(1)
# 
# q.put('lqz')
# q.put(18)
# q.put(19)
# q.put(20)
# # q.put(21)
# q.put_nowait(100)
# 
# # 从管道中取值
# print(q.get())
# print(q.get())
# print(q.get())
# print(q.get())
# print(q.get())
# print(q.get())
# # print(q.get(timeout=0.1))  # 等0.1s还没有值,就结束
# print(q.get_nowait())        # 不等了,有就是有,没有就没有
# print(q.queue)
# 
# 
# 
# print(q.empty())  # 看一下队列是不是空的
# print(q.full())   # 看一下队列是不是满的

PS 注意点:q=Queue(5) 括号内为队列值的个数,小于等于0不限制,若往里塞的个数q.put()大于这个值,则阻塞,q.get()为删除队列的值并返回,若删除不到,则报错,put_nowait,get_nowait 都是不等,直接操作,不行就报错,get(timeout = 0.1)等0.1秒,没有值就结束
# 总结:
'''
q=Queue(队列大小)
# 放值
q.put(asdf)
q.put_nowait(asdf)  # 队列满了,放不进去就不放了,报错

# 取值
q.get()  # 从队列头部取出一个值
q.get_nowait() # 从队列头部取值,没有就抛错


# 队列是否为空,是否满
print(q.empty())  # 看一下队列是不是空的
print(q.full())   # 看一下队列是不是满的
'''

IPC机制:进程间通信:Inter-Process Communication

from multiprocessing import Process, current_process, Queue
# import time
# import os
# 
# 
# def task1(q):
#     print('我是task1进程,我的id号是:%s'%os.getpid())
#     q.put('lqz is handsome')
# 
# 
# def task2(q):
# 
#     # res=q.get()
#     # print('我是task2进程,我的id号是:%s'%os.getpid(),res)
#     print('我是task2进程,我的id号是:%s'%os.getpid())
#     q.put('第二次通信')
#     # print(q.get())
# 
# if __name__ == '__main__':
#     q = Queue(5)
# 
#     t1 = Process(target=task1, args=(q,))
#     t1.start()
#     t1.join()
#     t2 = Process(target=task2, args=(q,))
#     t2.start()
# 
#     print(q.get())

PS:IPC机制,实现了进程之间的数据交换,但是子进程是异步的,执行速度有差异,数据存入管道中的速度也有差异,故取出的数据随机



















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值