首页 > 系统相关 >进入python的世界_day34_网络编程——同步与异步、进程、消息队列、互斥锁

进入python的世界_day34_网络编程——同步与异步、进程、消息队列、互斥锁

时间:2022-11-18 19:34:15浏览次数:35  
标签:__ Process name python day34 互斥 print 执行 进程

一、同步与异步、阻塞与非阻塞

1.同步与异步介绍

​ 一种方式,可以用来表示提交任务方提交任务后的行为

同步:好比去办车牌的时候,提交了资料就呆在大厅一动不动,等着审核结果出来

异步:好比去办车牌的时候,提交了资料后就留一个人在大厅等结果,另一个人出门去买水之类的

2.阻塞与非阻塞

其实也就是我们昨天学的阻塞态,意思就是任务卡住了

阻塞: 阻塞态

非阻塞:就绪态、运行态

3.搭配使用

主要看cpu还在不在身边,自己是不是呆着不动

同步阻塞、同步非阻塞

​ 前者啥都干不了,后者还能干些事情但是不能离开大厅

异步阻塞、异步非阻塞

​ 前者能干自己的事,也会有人通知结果是否出来,但是不能离开大厅去忙别的事

​ 后者最有用,效率最高

二、代码的方式创建多进程

前言:我们下的程序,一般都是可以打开多个的,每打开一个,就是打开了一个新进程

multiprocessing模块

核心模块:from multiprocessing import Process

# 代码实操
from multiprocessing import Process

import time

# 随便创一个函数打点东西

def a():
    print('任务正在执行')
    time.sleep(5)  # 手动阻塞一下
    print('任务执行完毕')


# 因为执行程序就是相当于复制一份拿到内存里去执行,为了防止反复导,我们在代码中加上main的主体代码
if __name__ == '__main__':
    p1 = Process(target=a)  # 创一个程序对象
    p1.start()  # 创建新进程
    print('主程序执行了')
    
  >>>
主程序执行了
任务正在执行
任务执行完毕
 ————————————————————————————

​ 注意,我们通过运行上面代码发现,主进程的print先打印,而子进程的print后打印,这是因为,当走到主进程创建子进程这一步,立马在内存空间中创建了一个子进程开始执行,但是同时主进程和子进程是异步操作,在子进程生效前主不会停下等子,所以主这边先打印,我们可以主动阻塞一下主进程,阻塞0.05s 、0.1s、1s都可以试试,发现确实子进程有一个生效时间

# 其他代码不变

if __name__ == '__main__':
    p1 = Process(target=a)  # 创一个程序对象
    p1.start()  # 创建新进程
    time.sleep(0.05)
    print('主程序执行了')

 >>>
主程序执行了
任务正在执行
任务执行完毕   # 发现第一句第二句出来的很快,但是依旧主先打
——————————————————————————————————————————
# 其他代码不变

if __name__ == '__main__':
    p1 = Process(target=a)  # 创一个程序对象
    p1.start()  # 创建新进程
    time.sleep(0.1)
    print('主程序执行了')

>>>
任务正在执行
主程序执行了
任务执行完毕   # 可以看到,子进程先打了,主被超车了

# 所以在该案例中大概有0.1s的时间子进程生效

传参形式的子进程

# 代码实操
from multiprocessing import Process

import time


# 创一个函数打点东西,但是需要传参

def a(name):
    print(f'{name}正在a进程执行任务')
    time.sleep(3)  # 手动阻塞一下
    print(f'{name}a进程任务执行完毕')


# 因为执行程序就是相当于复制一份拿到内存里去执行,为了防止反复导,我们在代码中加上main的主体代码
if __name__ == '__main__':
    p1 = Process(target=a, args=('jason',))  # 创一个程序对象,传参一定注意传参是框元组,逗号别省略!!!
    p1.start()  # 创建新进程
    print('主程序执行了')

>>>
主程序执行了
jason正在a进程执行任务
jasona进程任务执行完毕

玩玩类的创建进程

# 代码实操
from multiprocessing import Process

import time


# 创一个函数打点东西,但是需要传参
class A(Process):
    def __init__(self, name):
        super().__init__()  # super()看你想如何继承,是后修改还是先修改
        self.name = name

    def run(self):
        print(f'{self.name}正在执行任务')
        time.sleep(3)  # 手动阻塞一下
        print(f'{self.name}任务执行完毕')


# 因为执行程序就是相当于复制一份拿到内存里去执行,为了防止反复导,我们在代码中加上main的主体代码
if __name__ == '__main__':
    obj = A('jason')  # 新建一个对象
    obj.start()  # 创建新进程
    print('主程序执行了')

三、进程的方法

  • 进程间的数据是隔离的(默认情况下),具体看下面例子中的打印变量名c

1.join方法

​ 等待子进程执行完后再执行主进程代码

from multiprocessing import Process
import time
from multiprocessing import Queue

c = 1000


def a():
    print('a在执行')
    global c
    c = 666
    print('子进程内>>>:', c)
	time.sleep(3)

if __name__ == '__main__':
    p1 = Process(target=a)
    p1.start()  # 告诉操作系统创建一个新的进程,并执行
    p1.join()  # 主进程代码等待子进程代码运行结束再执行
    print('主在执行')
    print(c)  # 这个打印c只是打印主进程中的c,就算子进程改了主进程的依旧是老的c

>>>
a在执行
子进程内>>>: 666 # 先出现这两行
# 隔了三秒
主在执行
1000
___________________________________
# 注意 不管子进程用不用破界声明关键字,都不影响主进程!前面说过是复制代码到内存中,数据隔离,隔离,隔离(默认情况下)

2.查看进程的ID号

​ 可以用cmd,输入tasklist, 可以看到一排排的任务,有一栏是PID,这个就是进程ID号

在python中如何查看:

  • 用current_process模块——current_process().pid
  • 或者用os模块——os.getpid() 、os.getppid() 后者能获取主进程的ID号
from multiprocessing import Process, current_process
import time
from multiprocessing import Queue

c = 1000


def a():
    print(current_process())
    print(current_process().pid)
    print('a在执行')
    global c
    c = 666
    print('子进程内>>>:', c)
    time.sleep(3)


def b():
    print(current_process())
    print(current_process().pid)
    print('b在执行')


if __name__ == '__main__':
    p1 = Process(target=a)
    p1.start()  # 告诉操作系统创建一个新的进程,并执行
    p1.join()  # 主进程代码等待子进程代码运行结束再执行
    p2 = Process(target=b)
    p2.start()
    p2.join()
    print(current_process())
    print(current_process().pid)
    print('主在执行')
    print('主进程内>>>:', c)
>>>
<Process name='Process-1' parent=7596 started>
14232
a在执行
子进程内>>>: 666
<Process name='Process-2' parent=7596 started>
24180
b在执行
<_MainProcess name='MainProcess' parent=None started>
7596
主在执行
主进程内>>>: 1000

# ID号就显而易见了,parent是代表父进程

3.如何中止进程

​ 代码中:terminate() 终止子进程,当然,也是异步操作,所以如果主程序有延迟启动,可能终止的不及时

​ cmd中手动:taskkill /F /PID +ID /F是强制模式

  • 你也可以pycharm中先拿到进程ID,然后多阻塞一些,立马跑去cmd里去杀掉该ID的进程,也可以

4.判断进程是否还活着方法

​ is_alive()返回布尔值 同样注意异步情况

if __name__ == '__main__':
    obj = A('jason')  # 新建一个对象
    obj.start()  # 创建新进程
    obj.terminate()
    print(obj.is_alive())
    print('主程序执行了')

>>>
True    
主程序执行了
_______________________________________
if __name__ == '__main__':
    obj = A('jason')  # 新建一个对象
    obj.start()  # 创建新进程
    obj.terminate()
    time.sleep(0.01)   #  加一点点阻塞
    print(obj.is_alive())
    print('主程序执行了')

>>>
False
主程序执行了

四、消息队列(先了解)

1.含义

​ 临时保存数据的地方,类似公共的仓库,其实我们聊的微信这些程序都运用了高级的消息队列方法,假如我们下线了,别人发消息过来,我们上线后依旧可以收到并查看

2.代码

from multiprocessing import Queue

q = Queue(3)  # 指定仓库的容积
q.put(111)
q.put(222)
q.put(333)
print(q.get())
print(q.get())
print(q.get())
>>>
111
222
333
# 先进先出原则,取完就没了,但是再取不报错,会等着新进入数据
——————————————————————————————————————————————
# 几个小方法 
print(q.full())   # 判断仓库是否存满了 多进程中不能用
print(q.empty())  # 判断仓库是否是空的  多进程中不能用
print(q.get_nowait()) # 暴躁老哥,不给他就报错
# 实现了进程之间的信息交互
from multiprocessing import Process, Queue


def a(q):
    date = '黄焖鸡米饭'
    q.put(date)
    print(f'我是a,这是我添加的消息队列的数据 {date}')


def b(q):
    print('我是b,这是我能看到的消息队列的数据>>>:', q.get())


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

    p1 = Process(target=a, args=(q,))
    p2 = Process(target=b, args=(q,))
    p1.start()
    p2.start()
    print('我是主进程,执行了')
    
>>>
我是主进程,执行了
我是a,这是我添加的消息队列的数据 黄焖鸡米饭
我是b,这是我能看到的消息队列的数据>>>: 黄焖鸡米饭
    

五、守护进程

被守护进程会随着守护进程的结束而结束

守护经常的使用

from multiprocessing import Process, Queue
import time


def a(q):
    date = '黄焖鸡米饭'
    q.put(date)
    print(f'我是a,这是我添加的消息队列的数据 {date}')


def b(q):
    print('我是b,哈哈我还活着!')
    time.sleep(3)
    print('我是b进程,这是我能看到的消息队列的数据>>>:', q.get())


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

    p1 = Process(target=a, args=(q,))
    p2 = Process(target=b, args=(q,))
    p1.start()
    p2.daemon = True  # 设置p2子进程为主进程的守护进程
    p2.start()
    time.sleep(1)
    print('我是主进程,执行了')
    print('我是被守护进程,接下来我来终结守护进程') 

>>>
我是a,这是我添加的消息队列的数据 黄焖鸡米饭
我是b,哈哈我还活着!
我是主进程,执行了
我是被守护进程,接下来我来终结守护进程
# 可以看到,主进程结束后p2进程直接不执行了

六、僵尸进程和孤儿进程

1.僵尸进程

​ 主进程结束后其实不是真正的结束,而是等着所有子进程结束后回收一些信息后再结束

2.孤儿进程

​ 主进程以外嗝屁,子进程没有了父进程,这时候操作系统会派一个类似孤儿院的程序来接管这些子进程。

七、互斥锁

​ 当多个子进程去查询数据库的某个信息时,接收到的信息是请求的那个时间节点的,可能存在后续信息发送了变动,而子进程却没有再次查询,这样就会造成数据错乱

# 先创一个date.json,模拟一下数据库,里面有多少张票
from multiprocessing import Process
import time
import json
import random


# 查票
def search(name):
    with open(r'data.json', 'r', encoding='utf8') as f:
        data = json.load(f)
    print('%s在查票 当前余票为:%s' % (name, data.get('ticket_num')))


# 买票
def buy(name):
    # 再次确认票
    with open(r'data.json', 'r', encoding='utf8') as f:
        data = json.load(f)
    # print('当前余票为:%s' % (data.get('ticket_num')))
    # 模拟网络延迟
    time.sleep(random.randint(1, 3))
    # 判断是否有票 有就买
    if data.get('ticket_num') > 0:
        data['ticket_num'] -= 1
        with open(r'data.json', 'w', encoding='utf8') as f:
            json.dump(data, f)
        print('%s买票成功' % name)
    else:
        print('%s很倒霉 没有抢到票' % name)


def run(name):
    search(name)
    buy(name)


if __name__ == '__main__':
    for i in range(10):
        p = Process(target=run, args=('用户%s' % i,))
        p.start()

>>>
用户0在查票 当前余票为:1
用户1在查票 当前余票为:1
用户2在查票 当前余票为:1
用户3在查票 当前余票为:1
用户4在查票 当前余票为:1
用户5在查票 当前余票为:1
用户7在查票 当前余票为:1
用户6在查票 当前余票为:1
用户8在查票 当前余票为:1
用户9在查票 当前余票为:1
用户7买票成功
用户0买票成功
用户1买票成功用户2买票成功

用户4买票成功
用户8买票成功
用户3买票成功
用户9买票成功
用户6买票成功
用户5买票成功

# 可以看到很多BUG,只有一张票,但是所有人都显示买票成功

标签:__,Process,name,python,day34,互斥,print,执行,进程
From: https://www.cnblogs.com/wznn125ml/p/16904713.html

相关文章

  • python分析xmind的节点
     由于测试用例是xmind格式,工具只能查询到总的节点数,于是网上找了一段解析xmind的代码。如下(出处记不得了就没贴):#模块名称(文件名为:parse_xmind.py)importrequestsimp......
  • python爬虫实战一、爬取酷我音乐榜单并写入txt文件保存到本地
    python爬虫实战一、爬取酷我音乐榜单并写入txt文件保存到本地一、总代码和运行截图#加载需要的库importrequestsfrombs4importBeautifulSoupfromlxmlimportetreef=......
  • Python学习——小知识
    前言:因为没有系统学习过python语言,所以在看python代码的过程中十分吃力,因此决定把每次不懂的地方记录之,积土成山,积水成渊。1.判断变量的类型——​​isinstance()​​a=li......
  • python基础入门之进程
    python基础入门之进程目录python基础入门之进程阻塞与非阻塞同步与异步综合使用创建进程的多种方式进程间数据隔离进程的join方法IPC机制生产者消费模型进程对象的多种方......
  • Python 笔记
    Python笔记记录写Python需要注意的问题,以及一些技巧。在Python中EverythingisObject。Python中的模块standardmodulesbuilt-inmodulesdynamicmodules......
  • c++ 调用 python 数据类型对照表
    ParsingargumentsandbuildingvaluesThesefunctionsareusefulwhencreatingyourownextensionsfunctionsandmethods.Additionalinformationandexamplesa......
  • python-etcd
    安装pipinstallpython-etcdp查询所有的keys,或者以某个前缀的keysetcdctlget--prefix""etcdctlget--prefix "/nodes"只列出keys,不显示值etcdctlget--pre......
  • 加速python代码
    jupyter:jupytext:text_representation:extension:.mdformat_name:markdownformat_version:'1.2'jupytext_version:1.4.1kern......
  • python零基础入门教程(非常详细),从零基础入门到精通,看完这一篇就够了
    前言本文罗列了了python零基础入门到精通的详细教程,内容均以知识目录的形式展开。第一章:python基础之markdownTypora软件下载Typora基本使用Typora补充说明编程与编......
  • python每执行10次休息一会
       importtimen=0whilen<10:print(n,"删除数据成功")n=n+1ifn==10:n=0time.sleep(5)continueimportt......