プロセスプールとスレッドプール
コンピューターのパフォーマンスは制限されており、プロセスとスレッドを無期限に開くことはできません。
プロセスプールを作成して、コンピューターの許容範囲内で同時タスクの数を制御します
プロセスプール(マルチプロセスの計算集約型使用)
プログラム1
方案1:等进程全部运行完毕统一拿返回值,需要处理返回值结果时采用并发的形式去处理结果效率最高,比较占用计算机的资源
from concurrent.futures import ProcessPoolExecutor
import os, time, random
def task(n):
print("%s is running" % os.getpid())
time.sleep(random.randint(1, 3))
return n ** 2
if __name__ == '__main__':
# print(os.cpu_count()) # 查看计算机的cpu是几核的,本机是8核的
pool = ProcessPoolExecutor(
max_workers=8) # 主进程开启进程池,ProcessPoolExecutor()如果不传参的话计算机的cpu是几核的,那么就开几个进程,传参的话,传多少值就开几个进程。
l = []
for i in range(19): # 进程池里面有8个进程,从始至终都是者8个进程,进程池里面的进程不会运行完一个就直接结束掉,会等这19个任务全部运行完毕才会结束进程
future = pool.submit(task, i) # .submit是异步的方式提交任务,task是需要运行的函数,i是传入task的参数
l.append(future)
pool.shutdown(wait=True) # shutdown(统计进程池里面的进程个数,不允许在往进程池里面提交新的任务了),wait=True,每运行完一个任务就会减一,直到任务减成0,等待所有任务运行完毕
print("主")
for obj in l:
print(obj.result()) # obj.result()等任务运行完毕统一拿返回值,这种方式采用并发的形式处理结果效率最高
シナリオ2
方案2:利用回调函数让主进程去处理结果,每运行完一个进程,主进程就开启一个线程,这样对计算机资源的利用比较合理
from concurrent.futures import ProcessPoolExecutor
import os, time, random
def task(n):
print("%s is running" % os.getpid())
time.sleep(random.randint(1, 3))
return n ** 2
def handle(futrue):
res = futrue.result()
print("%s 正在处理结果:%s" % (os.getpid(), res))
time.sleep(2)
if __name__ == '__main__':
pool = ProcessPoolExecutor(max_workers=8)
for i in range(19):
pool.submit(task, i).add_done_callback(
handle) # .add_done_callback()回调函数,是指用来处理任务的函数,一旦一个任务运行完,会把运行完的结果当初参数传给被调的函数,会自动触发回调函数的运行
pool.shutdown(wait=True)
スレッドプールコードのデモンストレーション(ioを多用するマルチスレッド)
from concurrent.futures import ThreadPoolExecutor
from threading import current_thread
import time, random
def task(n):
print("%s is running" % current_thread().name)
time.sleep(random.randint(1, 3))
return n ** 2
def handle(futrue):
res = futrue.result()
print("%s 正在处理结果:%s" % (current_thread().name, res))
time.sleep(2)
if __name__ == '__main__':
pool = ThreadPoolExecutor(max_workers=10) # ThreadPoolExecutor()如果不传参数的话,开启线程的个数默认时cpu个数的5倍
for i in range(19):
pool.submit(task, i).add_done_callback(
handle) # .submit异步提交,.add_done_callback()回调函数,是指用来处理任务的函数,一旦一个任务运行完,会把运行完的结果当初参数传给被调的函数,会自动触发回调函数的运行
pool.shutdown(wait=True)
コルーチンは、シングルスレッドで達成される同時実行性です(シングルスレッドは最大500以上の同時実行性に耐えることができ
ます)。機能:独自のアプリケーションが複数のユーザーのスケジューリングを実現し、
ioスイッチングに遭遇します。これにより、シングルスレッドのioを最小にし、シングルスレッドの運用効率を向上させる
デメリット:
1。並列処理を実現できない
2.シングルスレッドで複数のタスクがioに遭遇すると、スレッド全体がブロックされ、すべてのタスクが停止します
2.共同プログラムの目的:
単一のスレッドで並行性を実現したい。
並行性とは、複数のタスクが同時に実行されているように見えることを意味します。
並行性=切り替え+状態の保存
协程代码演示
下载安装gevent第三方库(cmd命令行里面输入命令pip3 install gevent)
协程代码演示Gevent(底层原理是封装了yield,遇到io保存当下的状态后会自动切换)
from gevent import monkey;monkey.patch_all() # monkey.patch_all()会把代码所有的io行为转换成gevent能够识别的
import gevent
import time
def eat(name):
print("%s eat 1" % name)
time.sleep(2) # 遇到io后切换到play
print("%s eat 2" % name)
def play(name):
print("%s play 1" % name)
time.sleep(1) # 遇到io后切换到eat,play也在io状态会进行来回的切换
print("%s play 2" % name)
g1 = gevent.spawn(eat, "nana")
g2 = gevent.spawn(play, name="nana")
g1.join() # print("主")运行完单线程就运行结束了,所有要用join让线程等待协程运行完再结束
g2.join()
print("主")
コルーチンの同時ケースを実現するソケットプログラム
服务端
from gevent import monkey;monkey.path_all()
from socket import *
import gevent
def server(server_ip, port): # 链接请求
s = socket(AF_INET, SOCK_STREAM)
# s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
s.bind((server_ip, port)) # 绑定ip跟端口
s.listen(5) # 监听请求
while True:
conn, addr = s.accept() # 建立链接
gevent.spawn(talk, conn, addr) # 每建立一个链接提交一个协程对象,建立通信连接(异步提交)
def talk(conn, addr): # 通信请求
try:
while True:
res = conn.recv(1024)
print("client %s:%s msg:%s" % (addr[0], addr[1], res))
conn.send(res.upper())
except Exception as e:
print(e)
finally:
conn.close()
if __name__ == '__main__':
server("127.0.0.1", 8080)
客户端
__author__ = "上海吴彦祖"
from socket import *
client = socket(AF_INET, SOCK_STREAM)
client.connect(("127.0.0.1", 8080))
while True:
msg = input("输入:").strip()
if not msg: continue
client.send(msg.encode("utf-8"))
msg = client.recv(1024)
print(msg.decode("utf-8"))