python协程使用场景_Python篇-多进程与协程的理解与使用

TZ : 朴实的劳作也能硕果累累

一 : 科普一分钟

尽管进程间是独立存在的,不能相互访问彼此的数据,但是在python中却存在进程间的通信方法,来帮助我们可以利用多核CPU也能共享数据.

对于多线程其实也是存在一些缺点的,不是任何场景我们都用多线程来完成并发处理任务,因为CPU操作线程,所以线程多了,对于计算机的资源消耗是十分严重的,多线程适合IO操作密集的任务,那么怎么办呢, 协程的出现帮我们解决了这个问题 ,协程是比线程更小的一个单位,但是它的作用却不容忽视.

二 : 多进程

1. 多进程简单了解 :

进程之间是独立的,是操作系统自己来维护和管理的,python通过C接口起了一个进程,多进程可以充分的利用多核CPU

2. 多进程的创建 :

import multiprocessing

import time

# 子进程执行方法

def run(person):

time.sleep(2)

print(person)

#循环创建 10个子进程

for i in range(10):

#创建子进程实例

p = multiprocessing.Process(target=run,args=('雪芙 %s' %i ,))

#运行子进程

p.start()

3. 多进程间的通信 :

进程间独立,如果想相互访问,就必须有一个中间翻译,下面提供了几种进程间通信的方法

进程Queue

from multiprocessing import Process,Queue

# import queue

#子进程,内存独立,相当于数据的传递

def f(subQueue):

subQueue.put("雪芙")

if __name__ == '__main__':

#进程Queue

q = Queue()

#创建进程

p = Process(target=f,args=(q,))

#执行进程

p.start()

print(q.get())

解析 :

Queue通信,相当于父进程赋值了一个Queue给子进程,子进程在这个Queue放好数据后,序列化一个中间翻译,然后在反序列化返回给父进程,

因为进程之间内存独立,不能传递对象传递的其实就是序列化的数据

Pipe

多进程还有一种数据传递方式叫管道原理和 Queue相同

# Author:TianTianBaby

from multiprocessing import Process,Pipe

#子进程执行方法

def f(Subconn):

Subconn.send("吃了吗")

print("来自父亲的问候 : ",Subconn.recv())

Subconn.close()

if __name__ == '__main__':

#创建管道两端

parent_conn,child_conn = Pipe()

#创建子进程

p = Process(target=f,args=(child_conn,))

p.start()

print("来自儿子的问候 :",parent_conn.recv())

parent_conn.send("你好啊")

p.join()

4. 进程锁

虽然内存独立,但是即使是打印也会造成打印数据错误,为了防止进程间抢屏幕打印输出,加了进程锁

from multiprocessing import Process,Lock

#子进程执行方法

def f(lock,num):

lock.acquire()

print("tztztz",num)

lock.release()

if __name__ == '__main__':

lock = Lock()

#循环创建100个子进程

for num in range(100):

Process(target=f,args=(lock,num)).start()

5. 进程池

创建一个子进程相当于copy一份父进程内存数据,为了防止频繁创建,导致内存不足,所以有了进程池作为限制.

# Author:TianTianBaby

from multiprocessing import Process,Pool

import time,os

def son(i):

time.sleep(2)

return i+100

def Back(arg):

print('你好完成')

#允许进程池同时放入5个进程

pool = Pool(processes=3)

for i in range(10):

#并行 callback 回调(主进程调用的)

pool.apply_async(func=son,args=(i,),callback=Back)

#并行

# pool.apply_async(func=son, args=(i,))

#串行

# pool.apply(func=son,args=(i,))

print('end')

#先关闭进程池再join

pool.close()

#进程池中进程执行完毕再关闭,如果注释,那么程序直接关闭

pool.join()

三 : 协程

1. 协程的简单了解 :

协程又称微线程,coroutne,协程是一种用户态的轻量级线程

通俗点讲就是周末我在家里休息,假如我先洗漱,再煮饭,再下载电影看会很慢,用了协程的效果就好比,我在下载电影的时候去点火煮饭,此时我马上洗漱,等我洗漱好了,饭也好了,吃完饭了,电影下好了,我可以看了.

a4ac0c478be7

讲究效率的协程

2. 协程的创建和使用 :

gevent 是一个三方库,可以轻松通过gevent实现并发同步或者异步编程.

# Author:TianTianBaby

import gevent

#函数1

def first():

print('运行 1')

gevent.sleep(2)

print('回到1')#精确的文本内容切换到 ..

#函数2

def second():

print('运行2')

gevent.sleep(1)

print('回到2')

#函数3

def third():

print("运行3")

gevent.sleep(0)

print("回到3")

#创建并添加写成任务

gevent.joinall([gevent.spawn(first), #生成

gevent.spawn(second),

gevent.spawn(third)])

解析:尝试运行发现,运行时间为Sleep最长的时间,也就是说协程能绕过IO,进行执行,极大的提高了效率.

IO(从硬盘上读一块数据,从网络读数据,从内存里读一块数据) 操作不占用CPU,计算占用CPU

3. 协程简单爬网页 :

# Author:TianTianBaby

from urllib import request

import ssl

import gevent

from gevent import monkey

#把当前程序的所有的IO操作 单独做上标记

monkey.patch_all()

ssl._create_default_https_context = ssl._create_unverified_context

def f(url):

print('GET:%s' %url)

resp = request.urlopen(url)

print(resp)

data = resp.read()

f = open("pa.html","wb")

f.write(data)

f.close()

print("%d bytes received from %s" %(len(data),url))

gevent.joinall([gevent.spawn(f,'http://www.jianshu.com/'),

gevent.spawn(f,'http://www.iconfont.cn/'),

gevent.spawn(f,'http://www.cocoachina.com/'),

])

4. 协程实现socketServer:

通过协程,我们可以写出一个socketServer,真正socketServer的底层是用多线程来实现,我们用写成写出的效率很高,而且非常节省内存

import sys

import socket

import time

import gevent

from gevent import socket,monkey

monkey.patch_all()

def server(port):

s = socket.socket()

s.bind(('localhost',port))

s.listen(500)

while True:

cli,addr = s.accept()

#交给协程处理

gevent.spawn(handle_request,cli)

def handle_request(conn):

try:

while True:

data = conn.recv(1024)

print("recv:",data)

conn.send(data)

if not data:

conn.shutdown(socket.SHUT_WR)

except Exception as ex:

print(ex)

finally:

conn.close()

if __name__ == '__main__':

server(9001)

四 : 总结

协程的优点

1 : 线程在单线程下切换,减少资源消耗

2 : 无需原子操作控制流,简化编程模型

3 : 高并发,高扩展,低成本.

无论是多进程,多线程还是协程在不同的场景用不同的模型才能高效的完成任务.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值