我在Python中有以下代码,它将连续执行5个查询。每个查询的平均运行时间约为181.1秒(约3分钟),所有5个查询的总运行时间为905.4秒(约15分钟)。最终,在将数据加载到DataFrames中之后,我将执行ETL工作(主要是查找错误,数据质量问题和不一致),但是在此之前,我想尝试利用多处理来减少运行时。我对Python中的多重处理不熟悉,因此我一直在阅读有关不同方法的信息(队列与池等)。我很好奇哪种方法最适合此工作流程,我将如何实现呢?理想情况下,此代码的多过程翻译版本或到达那里的指南会很棒。
谢谢。
编辑:如果不清楚,我想同时运行所有5个查询。可能存在问题的是将每个DataFrame同时添加到列表中,因此,如果需要,我愿意放弃。
import pandas as pd
import psycopg2
import time
import os
host = os.environ["DBHOST"]
user = os.environ["DBUSER"]
pass = os.environ["DBPWD"]
db_conn = psycopg2.connect("host='{}' port={} dbname='{}' user={} password={}".format(host,
port#,
"db_name",
user,
pass))
query_load = [("SELECT column_name_1, COUNT(*) "
"FROM schema.table "
"GROUP BY column_name_1 "
"ORDER BY column_name_1 ASC"),
("SELECT column_name_2, COUNT(*) "
"FROM schema.table "
"GROUP BY column_name_2 "
"ORDER BY column_name_2 ASC"),
("SELECT column_name_3, COUNT(*) "
"FROM schema.table "
"GROUP BY column_name_3 "
"ORDER BY column_name_3 ASC"),
("SELECT column_name_4, COUNT(*) "
"FROM schema.table "
"GROUP BY column_name_4 "
"ORDER BY column_name_4 ASC"),
("SELECT column_name_5, COUNT(*) "
"FROM schema.table "
"GROUP BY column_name_5 "
"ORDER BY column_name_5 ASC")]
start_time = time.time()
data_load = []
for queries in query_load:
data_load.append(pd.read_sql(queries, db_conn))
elapsed_time = time.time() - start_time
print ("Job finished in {} seconds".format(elapsed_time))
答案 0 :(得分:1)
由于您已经有了查询集合,因此我们可以组织一个函数一次获取一个查询,但是通过使用Pool.map
,它们可以同时运行:
from multiprocessing import Pool
import pandas as pd
import time
# define query_load
# define db_conn
def read_sql(query):
return pd.read_sql(query, db_conn)
if __name__ == '__main__':
start_time = time.time()
with Pool(5) as p:
data_load = p.map(read_sql, query_load)
elapsed_time = time.time() - start_time
print ("Job finished in {} seconds".format(elapsed_time))
# carry on re-processing data_load
现在,我假设db_conn
将允许并发请求。
还请注意,p.map
会为您整理结果并将其加载到list
中。
答案 1 :(得分:0)
(作为对已接受答案的评论更好,但我对此没有足够的声誉)
来自 psycopg2 文档:https://www.psycopg.org/docs/usage.html#thread-safety
<块引用>libpq 连接不应该被 fork 进程使用,所以当使用诸如 multiprocessing 的模块或诸如 FastCGI 的 fork web 部署方法时,请确保在 fork 之后创建连接。
因此将连接对象传递给池是不安全的,相反,每个进程都应该创建一个新连接。