pandas的apply默认不并行因其本质是单线程迭代;强行多进程易触发picklingerror等序列化异常,因dataframe、闭包等不可安全跨进程传递。

为什么 apply 默认不并行,且直接加多进程会出错?
Pandas 的 apply 本质是单线程迭代,它不自带并行能力;强行用 multiprocessing 包裹 apply 函数常导致 PicklingError 或共享内存异常——因为 DataFrame、自定义闭包函数、类方法等通常不可序列化,子进程无法重建上下文。
常见错误现象包括:
TypeError: can't pickle _thread.RLock objects- 子进程中读不到全局变量或导入的模块
- 返回结果顺序错乱、索引丢失
根本原因不是 apply 写得不对,而是 Pandas 没设计成可安全分片 + 并行 + 自动拼接的接口。
用 dask.dataframe 替代 apply 是最稳的并行方案
dask.dataframe 把大 DataFrame 切成块(partition),每个块独立调用你的函数,最后自动 concat + 对齐索引,全程无需手动管理进程、序列化或锁。
使用前提很简单:
- 安装:
pip install dask - 把原 Pandas DataFrame 转成 Dask DataFrame:
df_dask = dd.from_pandas(df, npartitions=4) - 替换
apply为map_partitions(注意:不是apply)
示例(对每行做字符串清洗):
def clean_row(row):
row['text'] = row['text'].strip().lower()
return row
<p>result = df_dask.map_partitions(lambda part: part.apply(clean_row, axis=1)).compute()
</p>
关键点:
-
map_partitions接收的是整个子 DataFrame,不是单行,所以函数签名要匹配 -
.compute()才真正触发计算,之前只是构建任务图 -
npartitions建议设为 CPU 核心数的 2–4 倍,太多反而调度开销大
想用原生 Pandas + 多进程?绕过 apply,改用 concurrent.futures 分片处理
不碰 apply,自己切片、提交任务、合并结果,可控性高,也避开了序列化陷阱。
操作步骤:
- 用
np.array_split(df, n_jobs)把 DataFrame 拆成若干块 - 用
ProcessPoolExecutor提交每个块给你的函数(函数必须是顶层定义、无闭包) - 合并结果时用
pd.concat(..., ignore_index=False)保留原始索引
示例:
def process_chunk(chunk):
return chunk.assign(new_col=chunk['x'] ** 2)
<p>chunks = np.array_split(df, 4)
with ProcessPoolExecutor(max_workers=4) as executor:
results = list(executor.map(process_chunk, chunks))
df_result = pd.concat(results, ignore_index=False)
</p>
注意:
- 函数不能引用外部变量(如
config字典),需显式传参或改用functools.partial - 若函数依赖第三方库(如
requests),每个子进程都会重新 import,别在函数里做一次性初始化 - 小数据量(
别忽略:有些“自定义函数”其实有更快的向量化替代方案
很多你以为必须 apply 的逻辑,Pandas 或 NumPy 已内置高效实现:
- 字符串操作 → 用
df['col'].str.lower()而非apply(lambda x: x.lower()) - 条件赋值 → 用
np.where或df.loc[mask, 'col'] = value - 分组聚合 → 用
groupby().agg({...}),别apply里写循环
性能差距常达 10–100 倍。先确认是否真需要 Python 层逐行控制——比如调用外部 API、复杂正则、或依赖状态的逻辑,才是 apply 的合理场景。
真正容易被忽略的是:并行本身解决不了算法复杂度问题。如果自定义函数内部有 O(n²) 循环,再怎么并行也救不回来。先优化函数体,再考虑分发。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











