在 python 中循环处理时并行写入文件
Writing to a file parallely while processing in a loop in python
我有一个 65K 的 CSV 数据。我需要对每个 csv 行进行一些处理,最后生成一个字符串。我必须 write/append 文件中的那个字符串。
伪代码:
for row in csv_data:
processed_string = ...
file_pointer.write(processed_string + '\n')
如何并行执行此写入操作 运行 以便主处理操作不必包括写入文件所花费的时间?我尝试使用批写入(存储 n 行,然后同时写入)。但是,如果您能建议我一些可以并行执行此操作的方法,那就太好了。谢谢!
编辑: 一个csv文件中有65K条记录。我正在处理它生成一个字符串(多行约 10-12)。我必须将它写入文件。对于 65K 条记录,得到每条 10-15 行的结果。通常代码需要 10 分钟才能完成 运行。但是添加此文件操作会将时间增加到 +2-3 分钟。那么我是否可以在不影响代码执行的情况下并行执行呢?
这是代码部分。
for i in range(len(queries)): # 65K runs
Logs.log_query(i, name, version)
# processed_results = Some processing ...
# Final Answer
s = final_results(name, version, processed_results) # Returns a multiline string
f.write(s + '\n')
"""
EXAMPLE OUTPUT:
-----------------
[0] NAME: Adobe Acrobat Reader DC | VERSION: 21.005
FAISS RESULTS (with cutoff 0.63)
id name version eol_date extended_eol_date major_version minor_version score
1486469 Adobe Acrobat Reader DC 21.005.20054 07-04-2020 07-07-2020 21 005 0.966597
327901 Adobe Acrobat Reader DC 21.005.20048 07-04-2020 07-07-2020 21 005 0.961541
327904 Adobe Acrobat Reader DC 21.007.20095 07-04-2020 07-07-2020 21 007 0.960825
327905 Adobe Acrobat Reader DC 21.007.20099 07-04-2020 07-07-2020 21 007 0.960557
327902 Adobe Acrobat Reader DC 21.005.20060 07-04-2020 07-07-2020 21 005 0.958580
327900 Adobe Acrobat Reader DC 21.001.20145 07-04-2020 07-07-2020 21 001 0.956085
327903 Adobe Acrobat Reader DC 21.007.20091 07-04-2020 07-07-2020 21 007 0.954148
1486465 Adobe Acrobat Reader DC 20.006.20034 07-04-2020 07-07-2020 20 006 0.941820
1486459 Adobe Acrobat Reader DC 19.012.20035 07-04-2020 07-07-2020 19 012 0.928502
1486466 Adobe Acrobat Reader DC 20.012.20048 07-04-2020 07-07-2020 20 012 0.928366
1486458 Adobe Acrobat Reader DC 19.012.20034 07-04-2020 07-07-2020 19 012 0.925761
1486461 Adobe Acrobat Reader DC 19.021.20047 07-04-2020 07-07-2020 19 021 0.922519
1486463 Adobe Acrobat Reader DC 19.021.20049 07-04-2020 07-07-2020 19 021 0.919659
1486462 Adobe Acrobat Reader DC 19.021.20048 07-04-2020 07-07-2020 19 021 0.917590
1486464 Adobe Acrobat Reader DC 19.021.20061 07-04-2020 07-07-2020 19 021 0.912260
1486460 Adobe Acrobat Reader DC 19.012.20040 07-04-2020 07-07-2020 19 012 0.909160
1486457 Adobe Acrobat Reader DC 15.008.20082 07-04-2020 07-07-2020 15 008 0.902536
327899 Adobe Acrobat DC 21.007.20099 07-04-2020 07-07-2020 21 007 0.895940
1277732 Acrobat Reader DC (classic) 2015 07-07-2020 * 2015 NaN 0.875471
OPEN SEARCH RESULTS (with cutoff 13)
{ "score": 67.98198, "id": 327901, "name": Adobe Acrobat Reader DC, "version": 21.005.20048, "eol_date": 2020-04-07, "extended_eol_date": 2020-07-07 }
{ "score": 66.63623, "id": 327902, "name": Adobe Acrobat Reader DC, "version": 21.005.20060, "eol_date": 2020-04-07, "extended_eol_date": 2020-07-07 }
{ "score": 65.96028, "id": 1486469, "name": Adobe Acrobat Reader DC, "version": 21.005.20054, "eol_date": 2020-04-07, "extended_eol_date": 2020-07-07 }
FINAL ANSWER [OPENSEARCH]
{ "score": 67.98198, "id": 327901, "name": Adobe Acrobat Reader DC, "version": 21.005.20048, "eol_date": 2020-04-07, "extended_eol_date": 2020-07-07 }
----------------------------------------------------------------------------------------------------
"""
Q : " Writing to a file parallely while processing in a loop in python ... "
A :
坦率地说,file-I/O不是你的performance-related敌人。
"With all due respect to the colleagues, Python (since ever) used GIL-lock to avoid any level of concurrent execution ( actually re-SERIAL-ising the code-execution flow into dancing among any amount of threads, lending about 100 [ms] of code-interpretation time to one-AFTER-another-AFTER-another, thus only increasing the interpreter's overhead times ( and devastating all pre-fetches into CPU-core caches on each turn ... paying the full mem-I/O costs on each next re-fetch(es) ). So threading is ANTI-pattern in python (except, I may accept, for network-(long)-transport latency masking ) – user3666197 44 mins ago "
考虑到 CSV 中列出的 65k 文件应该尽快处理,performance-tuned 编排是目标,file-I/O 可以忽略不计(而且 by-design 好 latency-maskable ) 其中的一部分 (这并不意味着,我们不能再搞砸了(如果试图在另一个 performance-devastating ANTI-pattern 中组织它,我们可以吗?)
提示 #1: 如果性能是目标,请避免并抵制使用任何 low-hanging 水果 SLOC
如果代码以 cheapest-ever iterator-clause、
开头,无论是 mock-up for aRow in aCsvDataSET: ...
还是 real-code for i in range( len( queries ) ): ...
- 这些(除了众所周知的 python code-interpretation 能力的一部分非常慢之外,第二个甚至是 iterator-on-range()-迭代器Py3 甚至是 Py2 生态系统中任何更大范围的沉默 RAM-killer)在“structured-programming”传播中看起来不错,因为它们形成 syntax-compliant 分离的 deeper-level 部分代码,但由于重复支付 overhead-costs 积累,它以非常高的成本影响这样做。最终注入的需要“协调”无序的并发 file-I/O 操作,原则上根本不需要,如果聪明地完成,如果这样一个微不足道的 SLOC(以及类似的糟糕设计决策)是不利性能影响的一个例子正在使用。
更好的方法?
- a ) 避免 top-level (慢 & overhead-expensive) 循环
- b ) 将 65k 参数 space“拆分”成不比物理设备上存在的 memory-I/O-channels 多多少块(评分过程,我可以从发布的文本中猜到,memory-I/O 密集,因为某些模型必须通过所有文本才能进行评分)
- c ) spawn
n_jobs
-many process workers,这将 joblib.Parallel( n_jobs = ... )( delayed( <_scoring_fun_> )( block_start, block_end, ...<_params_>... ) )
和 运行 scoring_fun(...)
这样分布的 block-part 的 65k-long参数 space.
- d ) 计算了分数和相关输出后,每个 worker-process 可以并且应该 file-I/O 在其私有的、专有的、conflicts-prevented 输出文件中
自己的结果]
- e ) 完成所有部分 block-parts 的处理后,
main
-Python 进程可以加入已经创建的 ( just-[CONCURRENTLY] 顺利 & non-blocking-ly O/S-buffered / interleaved-flow, real-hardware-deposited ) 存储输出,如果有这样的需求是...,
和
finito - 我们完成了(知道没有更快的方法来计算相同的 block-of-tasks,它们主要是独立的,除了需要用 minimised-add-on-costs 编排它们 collision-free)。
如果对感兴趣,
从lstopo
-map
开始,然后验证物理memory-I/O-channels
和
可以用Python joblib.Parallel()
-process instantiation, under-subscribing or over-subscribing the n_jobs
略低或略高于物理数memory-I/O-channels。如果实际处理有一些对我们隐藏的可屏蔽延迟,则可能有机会产生更多 n_jobs
-worker,直到 End-to-End 处理性能持续稳定增长,直到 system-noise 隐藏任何此类进一步 performance-tweaking 影响
A Bonus 部分 - 为什么 un-managed 延迟来源会破坏性能
我有一个 65K 的 CSV 数据。我需要对每个 csv 行进行一些处理,最后生成一个字符串。我必须 write/append 文件中的那个字符串。
伪代码:
for row in csv_data:
processed_string = ...
file_pointer.write(processed_string + '\n')
如何并行执行此写入操作 运行 以便主处理操作不必包括写入文件所花费的时间?我尝试使用批写入(存储 n 行,然后同时写入)。但是,如果您能建议我一些可以并行执行此操作的方法,那就太好了。谢谢!
编辑: 一个csv文件中有65K条记录。我正在处理它生成一个字符串(多行约 10-12)。我必须将它写入文件。对于 65K 条记录,得到每条 10-15 行的结果。通常代码需要 10 分钟才能完成 运行。但是添加此文件操作会将时间增加到 +2-3 分钟。那么我是否可以在不影响代码执行的情况下并行执行呢?
这是代码部分。
for i in range(len(queries)): # 65K runs
Logs.log_query(i, name, version)
# processed_results = Some processing ...
# Final Answer
s = final_results(name, version, processed_results) # Returns a multiline string
f.write(s + '\n')
"""
EXAMPLE OUTPUT:
-----------------
[0] NAME: Adobe Acrobat Reader DC | VERSION: 21.005
FAISS RESULTS (with cutoff 0.63)
id name version eol_date extended_eol_date major_version minor_version score
1486469 Adobe Acrobat Reader DC 21.005.20054 07-04-2020 07-07-2020 21 005 0.966597
327901 Adobe Acrobat Reader DC 21.005.20048 07-04-2020 07-07-2020 21 005 0.961541
327904 Adobe Acrobat Reader DC 21.007.20095 07-04-2020 07-07-2020 21 007 0.960825
327905 Adobe Acrobat Reader DC 21.007.20099 07-04-2020 07-07-2020 21 007 0.960557
327902 Adobe Acrobat Reader DC 21.005.20060 07-04-2020 07-07-2020 21 005 0.958580
327900 Adobe Acrobat Reader DC 21.001.20145 07-04-2020 07-07-2020 21 001 0.956085
327903 Adobe Acrobat Reader DC 21.007.20091 07-04-2020 07-07-2020 21 007 0.954148
1486465 Adobe Acrobat Reader DC 20.006.20034 07-04-2020 07-07-2020 20 006 0.941820
1486459 Adobe Acrobat Reader DC 19.012.20035 07-04-2020 07-07-2020 19 012 0.928502
1486466 Adobe Acrobat Reader DC 20.012.20048 07-04-2020 07-07-2020 20 012 0.928366
1486458 Adobe Acrobat Reader DC 19.012.20034 07-04-2020 07-07-2020 19 012 0.925761
1486461 Adobe Acrobat Reader DC 19.021.20047 07-04-2020 07-07-2020 19 021 0.922519
1486463 Adobe Acrobat Reader DC 19.021.20049 07-04-2020 07-07-2020 19 021 0.919659
1486462 Adobe Acrobat Reader DC 19.021.20048 07-04-2020 07-07-2020 19 021 0.917590
1486464 Adobe Acrobat Reader DC 19.021.20061 07-04-2020 07-07-2020 19 021 0.912260
1486460 Adobe Acrobat Reader DC 19.012.20040 07-04-2020 07-07-2020 19 012 0.909160
1486457 Adobe Acrobat Reader DC 15.008.20082 07-04-2020 07-07-2020 15 008 0.902536
327899 Adobe Acrobat DC 21.007.20099 07-04-2020 07-07-2020 21 007 0.895940
1277732 Acrobat Reader DC (classic) 2015 07-07-2020 * 2015 NaN 0.875471
OPEN SEARCH RESULTS (with cutoff 13)
{ "score": 67.98198, "id": 327901, "name": Adobe Acrobat Reader DC, "version": 21.005.20048, "eol_date": 2020-04-07, "extended_eol_date": 2020-07-07 }
{ "score": 66.63623, "id": 327902, "name": Adobe Acrobat Reader DC, "version": 21.005.20060, "eol_date": 2020-04-07, "extended_eol_date": 2020-07-07 }
{ "score": 65.96028, "id": 1486469, "name": Adobe Acrobat Reader DC, "version": 21.005.20054, "eol_date": 2020-04-07, "extended_eol_date": 2020-07-07 }
FINAL ANSWER [OPENSEARCH]
{ "score": 67.98198, "id": 327901, "name": Adobe Acrobat Reader DC, "version": 21.005.20048, "eol_date": 2020-04-07, "extended_eol_date": 2020-07-07 }
----------------------------------------------------------------------------------------------------
"""
Q : " Writing to a file parallely while processing in a loop in python ... "
A :
坦率地说,file-I/O不是你的performance-related敌人。
"With all due respect to the colleagues, Python (since ever) used GIL-lock to avoid any level of concurrent execution ( actually re-SERIAL-ising the code-execution flow into dancing among any amount of threads, lending about 100 [ms] of code-interpretation time to one-AFTER-another-AFTER-another, thus only increasing the interpreter's overhead times ( and devastating all pre-fetches into CPU-core caches on each turn ... paying the full mem-I/O costs on each next re-fetch(es) ). So threading is ANTI-pattern in python (except, I may accept, for network-(long)-transport latency masking ) – user3666197 44 mins ago "
考虑到 CSV 中列出的 65k 文件应该尽快处理,performance-tuned 编排是目标,file-I/O 可以忽略不计(而且 by-design 好 latency-maskable ) 其中的一部分 (这并不意味着,我们不能再搞砸了(如果试图在另一个 performance-devastating ANTI-pattern 中组织它,我们可以吗?)
提示 #1: 如果性能是目标,请避免并抵制使用任何 low-hanging 水果 SLOC
如果代码以 cheapest-ever iterator-clause、
开头,无论是 mock-up for aRow in aCsvDataSET: ...
还是 real-code for i in range( len( queries ) ): ...
- 这些(除了众所周知的 python code-interpretation 能力的一部分非常慢之外,第二个甚至是 iterator-on-range()-迭代器Py3 甚至是 Py2 生态系统中任何更大范围的沉默 RAM-killer)在“structured-programming”传播中看起来不错,因为它们形成 syntax-compliant 分离的 deeper-level 部分代码,但由于重复支付 overhead-costs 积累,它以非常高的成本影响这样做。最终注入的需要“协调”无序的并发 file-I/O 操作,原则上根本不需要,如果聪明地完成,如果这样一个微不足道的 SLOC(以及类似的糟糕设计决策)是不利性能影响的一个例子正在使用。
更好的方法?
- a ) 避免 top-level (慢 & overhead-expensive) 循环
- b ) 将 65k 参数 space“拆分”成不比物理设备上存在的 memory-I/O-channels 多多少块(评分过程,我可以从发布的文本中猜到,memory-I/O 密集,因为某些模型必须通过所有文本才能进行评分)
- c ) spawn
n_jobs
-many process workers,这将joblib.Parallel( n_jobs = ... )( delayed( <_scoring_fun_> )( block_start, block_end, ...<_params_>... ) )
和 运行scoring_fun(...)
这样分布的 block-part 的 65k-long参数 space. - d ) 计算了分数和相关输出后,每个 worker-process 可以并且应该 file-I/O 在其私有的、专有的、conflicts-prevented 输出文件中 自己的结果]
- e ) 完成所有部分 block-parts 的处理后,
main
-Python 进程可以加入已经创建的 ( just-[CONCURRENTLY] 顺利 & non-blocking-ly O/S-buffered / interleaved-flow, real-hardware-deposited ) 存储输出,如果有这样的需求是...,
和
finito - 我们完成了(知道没有更快的方法来计算相同的 block-of-tasks,它们主要是独立的,除了需要用 minimised-add-on-costs 编排它们 collision-free)。
如果对
从lstopo
-map
开始,然后验证物理memory-I/O-channels
和
可以用Python joblib.Parallel()
-process instantiation, under-subscribing or over-subscribing the n_jobs
略低或略高于物理数memory-I/O-channels。如果实际处理有一些对我们隐藏的可屏蔽延迟,则可能有机会产生更多 n_jobs
-worker,直到 End-to-End 处理性能持续稳定增长,直到 system-noise 隐藏任何此类进一步 performance-tweaking 影响
A Bonus 部分 - 为什么 un-managed 延迟来源会破坏性能