进程vs线程

进程vs线程创建速度

from threading import Thread
from multiprocessing import Process
import time

def task(name):
    print(f'{name} is running')
    time.sleep(2)
    print(f'{name} is end')


if __name__ == '__main__':
    t = Thread(target=task,args=('子线程',))
    p = Process(target=task,args=('子进程',))
    # t.start()
    p.start()
    print('主')

开启子线程的打印效果:

  • 子线程 is running

  • 主子线程 is end

开启子进程打印效果:

  • 主子进程 is running

  • 子进程 is end

进程和线程的创建速度

  • 开启子进程需要申请资源开辟空间

  • 开启子线程只是告诉操作系统一个执行方案

多线程vs多进程

计算密集型

from threading import Thread
from multiprocessing import Process
import time

# 计算密集型
# def work1():
#     res=0
#     for i in range(100000000): #1+8个0
#         res*=i
#
# if __name__ == '__main__':
#     t_list = []
#     start = time.time()
#     for i in range(4):
#         # t = Thread(target=work1)
#         t = Process(target=work1)
#         t_list.append(t)
#         t.start()
#     for t in t_list:
#         t.join()
#     end = time.time()
#     # print('多线程',end-start) # 多线程 15.413789510726929
#     print('多进程',end-start) # 多进程 4.711405515670776

IO密集型

# # io密集型
# def work1():
#     x = 1+1
#     time.sleep(5)
#
#
# if __name__ == '__main__':
#     t_list = []
#     start = time.time()
#     for i in range(4):
#         t = Thread(target=work1)
#         # t = Process(target=work1)
#         t_list.append(t)
#         t.start()
#     for t in t_list:
#         t.join()
#     end = time.time()
#     print('多线程',end-start) #  多线程 5.002625942230225
#     # print('多进程',end-start) # 多进程 5.660863399505615


进程池&线程池

前言:

'''重点掌握概念
1、什么时候用池:
池的功能是限制启动的进程数或线程数,
什么时候应该限制???
当并发的任务数远远超过了计算机的承受能力时,即无法一次性开启过多的进程数或线程数时
就应该用池的概念将开启的进程数或线程数限制在计算机可承受的范围内。

2、同步vs异步
同步、异步指的是提交任务的两种方式

同步:提交完任务后就在原地等待,直到任务运行完毕后拿到任务的返回值,再继续运行下一行代码
异步:提交完任务(可以绑定一个回调函数来实现)后根本就不在原地等待,直接运行下一行代码,等到任务有返回值后会自动触发回调函数
回调机制:任务执行中处于某种机制的情况自动触发回调函数。

Python标准模块--concurrent.futures

https://docs.python.org/dev/library/concurrent.futures.html

1 介绍

concurrent.futures模块提供了高度封装的异步调用接口
ThreadPoolExecutor:线程池,提供异步调用
ProcessPoolExecutor: 进程池,提供异步调用
Both implement the same interface, which is defined by the abstract Executor class.

2 基本方法

submit(fn, *args, **kwargs)

异步提交任务

map(func, *iterables, timeout=None, chunksize=1)

取代for循环submit的操作

shutdown(wait=True)

相当于进程池的pool.close()+pool.join()操作
wait=True,等待池内所有任务执行完毕回收完资源后才继续
wait=False,立即返回,并不会等待池内的任务执行完毕
但不管wait参数为何值,整个程序都会等到所有任务执行完毕
submit和map必须在shutdown之前

result(timeout=None)

取得结果

add_done_callback(fn)

回调函数
进程池/线程池的基本用法

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
from threading import currentThread
from multiprocessing import current_process
import time,os

def task(i):
# print(f'{currentThread().name} 在运行 任务{i}')
print(f'{current_process().name} 在运行 任务{i}')
time.sleep(0.2)
return i**2

if name == 'main':
pool = ProcessPoolExecutor(4)
fu_list = []
for i in range(20):
future = pool.submit(task,i)
# print(future.result()) # 拿不到值会阻塞在这里。
fu_list.append(future)

pool.shutdown(wait=True)  # 等待池内所有任务执行完毕
for i in fu_list:
    print(i.result())# 拿不到值会阻塞在这里。

回调函数

from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
from threading import currentThread
from multiprocessing import current_process
import time,os

def task(i):
# print(f'{currentThread().name} 在运行 任务{i}')
print(f'{current_process().name} 在运行 任务{i}')
time.sleep(0.2)
return i**2
def parse(future):
# print(future.result())
# print(currentThread().name,'拿到了结果',future.result()) # 如果是线程池 执行完当前任务 负责执行回调函数的是执行任务的线程。
print(current_process().name,'拿到了结果',future.result()) # 如果是进程池 执行完当前任务 负责执行回调函数的是执行任务的是主进程

if name == 'main':
pool = ProcessPoolExecutor(4)
# pool = ThreadPoolExecutor(4)
fu_list = []
for i in range(20):
future = pool.submit(task,i)
future.add_done_callback(parse) # 绑定回调函数
# 当任务执行结束拿到返回值的时候自动触发回调函数。并且把future当做参数直接传给回调函数parse