模拟并发任务,观察多进程和多线程的cpu使用率(以及进程池的chunksize参数)

1. 多进程 vs 多线程
import threading
import concurrent.futures

def kai(n):
    while True:
        if n != 0:
            n+=1
    print(n)


#ex = concurrent.futures.ThreadPoolExecutor(max_workers=5)  # 用线程
ex = concurrent.futures.ProcessPoolExecutor(max_workers=5)  # 用进程

ex_feature = ex.map(kai,[1,2,3,4,5])

print(ex_feature)

上述脚本可以验证对于纯计算类场景,对进程和多线程的效率差别(其实是对于cpu的充分使用程度)。

但是并不是说多进程有多鸡肋,在IO密集的场景下:多线程在遇到IO等待时会释放GIL锁让其他线程有执行机会,还是可以充分提升任务执行效率的。而且多线程较多进程更为轻量,更适合IO密集场景下高并发量的并行处理场景。


2. 验证excutor.map()中的chunksize参数的效果

对0-100000之间能被3整除的数进行过滤,4个子进程

import concurrent.futures

def li(n):
    if n % 3 == 0:
        return n

data=range(100000)
ex = concurrent.futures.ProcessPoolExecutor(max_workers=4)
#ex_feature = ex.map(li,data,chunksize=25000)
ex_feature = ex.map(li,data)

#print(ex_feature)

#with open('/tmp/result_with_chunk', 'w') as f:  #用chunksize时的结果文件
with open('/tmp/result_no_chunk', 'w') as f:     #不用chunksize时的结果文件
    for i in ex_feature:
        if i:
            f.write('{} '.format(i))

然后通过系统time命令观察耗时

~]# time python3 /tmp/tt.py     #no chunksize

real    0m18.694s
user    0m26.665s
sys     0m4.836s

~]# time python3 /tmp/tt.py     #with chunksize

real    0m0.227s
user    0m0.288s
sys     0m0.055s

对比结果文件,完全一致
~]# diff /tmp/result_with_chunk /tmp/result_no_chunk 
~]#

可以看到,在用或不用chunksize参数时,两者效率简直无法相比

待深入:chunksize的合理性(依据工作进程数,待处理数据总数等因素)


3 两种进程池写法
  1. concurrent.futures.ProcessPoolExecutor()
  2. multiprocessing.pool.Pool()
# test1方式1
from multiprocessing import Pool

def li(n):
    if n % 3 == 0:
        return n

data=range(10000000)
with Pool(5) as p:
    p.map(li,data,chunksize=2000000)
# test2方式2
import concurrent.futures

def li(n):
    if n % 3 == 0:
        return n

data=range(10000000)
ex = concurrent.futures.ProcessPoolExecutor(max_workers=4)
ex.map(li,data,chunksize=2500000)

执行结果(各执行3次)

 ~]$ time python3 /tmp/test1

real    0m1.582s
user    0m2.786s
sys     0m0.709s
 ~]$ time python3 /tmp/test1

real    0m1.627s
user    0m2.779s
sys     0m0.717s
 ~]$ time python3 /tmp/test1

real    0m1.583s
user    0m2.776s
sys     0m0.711s
 ~]$ time python3 /tmp/test2

real    0m8.056s
user    0m10.067s
sys     0m1.783s
 ~]$ time python3 /tmp/test2

real    0m7.961s
user    0m10.094s
sys     0m1.736s
 ~]$ time python3 /tmp/test2

real    0m7.981s
user    0m10.090s
sys     0m1.671s

看到方式1比方式2效率要高几倍

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Python 中,可以使用多线程多进程来提高从数据库读取大量数据的速。选择使用多线程还是多程取决于具体的应用场和需求。 使用多线程读取时,可以使用 `threading` 模块创建和管理线程。每个线程责读取数据库中的一部分,并将其存储在适当的数据构中。这样可以同时读取多个块,从而提高读取速度。需要注意的是,如果数据库连接是共享的,需要考虑线程安全性。 下面是一个简单的示例代码,使用多线程从数据库中读取数据: ```python import threading import pymysql # 设置数据库连接参数 db_config = { 'host': 'localhost', 'user': 'username', 'password': 'password', 'database': 'database_name' } # 定义线程类 class DataReaderThread(threading.Thread): def __init__(self, start, end): super().__init__() self.start = start self.end = end def run(self): # 创建数据库连接 conn = pymysql.connect(**db_config) cursor = conn.cursor() # 查询数据 query = f"SELECT * FROM table_name LIMIT {self.start}, {self.end - self.start}" cursor.execute(query) result = cursor.fetchall() # 处理数据 # ... # 关闭连接 cursor.close() conn.close() # 设置线程数量和数据分块大小 num_threads = 4 chunk_size = 10000 # 创建线程并启动 threads = [] for i in range(num_threads): start = i * chunk_size end = (i + 1) * chunk_size thread = DataReaderThread(start, end) thread.start() threads.append(thread) # 等待所有线程完成 for thread in threads: thread.join() ``` 与多线程相比,多进程可以更好地利用多核处理器的优势,适用于计算密集型任务。使用多进程读取数据时,可以使用 `multiprocessing` 模块来创建和管理进程。每个进程独立地读取数据库的一部分数据,并进行相应的处理。需要注意的是,不同进程之间的数据共享需要通过进程间通信机制来实现。 以下是一个简单的示例代码,使用多进程从数据库中读取数据: ```python import multiprocessing import pymysql # 设置数据库连接参数 db_config = { 'host': 'localhost', 'user': 'username', 'password': 'password', 'database': 'database_name' } # 定义进程函数 def data_reader(start, end, result_queue): # 创建数据库连接 conn = pymysql.connect(**db_config) cursor = conn.cursor() # 查询数据 query = f"SELECT * FROM table_name LIMIT {start}, {end - start}" cursor.execute(query) result = cursor.fetchall() # 处理数据 # ... # 将结果放入队列 result_queue.put(result) # 关闭连接 cursor.close() conn.close() # 设置进程数量和数据分块大小 num_processes = 4 chunk_size = 10000 # 创建进程和结果队列 pool = multiprocessing.Pool(processes=num_processes) result_queue = multiprocessing.Queue() # 提交任务进程 for i in range(num_processes): start = i * chunk_size end = (i + 1) * chunk_size pool.apply_async(data_reader, (start, end, result_queue)) # 关闭进程,等待所有任务完成 pool.close() pool.join() # 处理结果队列中的数据 while not result_queue.empty(): result = result_queue.get() # 处理数据 # ... ``` 需要根据具体的场景和需求选择使用多线程多进程多线程适用于 I/O 密集型任务,而多进程适用于计算密集型任务。在进行数据库读取时,多线程可能更适合,因为数据库的读取操作通常是 I/O 密集型的。然而,在某些情况下,多进程也可以提供更好的性能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值