PyCharm运行concurrent.futures官方示例报Pickling错误,Spyder正常
问题原因
Windows系统下,ProcessPoolExecutor使用spawn方式创建子进程,需要将主进程中的函数序列化后传递给子进程。PyCharm的某些运行模式下,脚本的__main__模块结构特殊,导致子进程无法在__main__中找到is_prime函数的定义,从而触发Pickling错误。而Spyder的运行环境会将脚本作为标准模块加载,子进程可以正确解析函数的归属,因此不会报错。
解决方法
方法1:将函数拆分到独立模块(推荐)
把is_prime函数放到单独的Python模块中,主脚本通过导入使用。这样子进程可以直接从模块中导入函数,避免依赖__main__模块的属性查找:
- 创建
primes.py文件,内容如下:
import math def is_prime(n): if n < 2: return False if n == 2: return True if n % 2 == 0: return False sqrt_n = int(math.floor(math.sqrt(n))) for i in range(3, sqrt_n + 1, 2): if n % i == 0: return False return True
- 修改主脚本代码,导入该函数:
import concurrent.futures from primes import is_prime PRIMES = [ 112272535095293, 112582705942171, 112272535095293, 115280095190773, 115797848077099, 1099726899285419] def main(): with concurrent.futures.ProcessPoolExecutor() as executor: for number, prime in zip(PRIMES, executor.map(is_prime, PRIMES)): print('%d is prime: %s' % (number, prime)) if __name__ == '__main__': main()
方法2:调整PyCharm运行配置
确保PyCharm以脚本路径模式运行你的代码,而非模块或交互式模式:
- 打开
Run -> Edit Configurations - 在配置列表中找到你的脚本配置
- 确认
Configuration标签下的Script path指向你的脚本文件(而非Module name选项) - 点击
Apply保存配置后重新运行
方法3:替换默认Pickler为cloudpickle
如果不想拆分模块,可以修改ProcessPoolExecutor的序列化逻辑,使用cloudpickle替代默认的pickle:
import concurrent.futures import math import cloudpickle from concurrent.futures.process import _ProcessPoolExecutor PRIMES = [ 112272535095293, 112582705942171, 112272535095293, 115280095190773, 115797848077099, 1099726899285419] def is_prime(n): if n < 2: return False if n == 2: return True if n % 2 == 0: return False sqrt_n = int(math.floor(math.sqrt(n))) for i in range(3, sqrt_n + 1, 2): if n % i == 0: return False return True # 自定义Executor,使用cloudpickle序列化 class CloudPickleExecutor(_ProcessPoolExecutor): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._mp_context.reducer = cloudpickle.reducer def main(): with CloudPickleExecutor() as executor: for number, prime in zip(PRIMES, executor.map(is_prime, PRIMES)): print('%d is prime: %s' % (number, prime)) if __name__ == '__main__': main()
注意:此方法依赖cloudpickle库,需先通过pip install cloudpickle安装。
内容的提问来源于stack exchange,提问作者George
相关产品推荐
相关产品推荐

