在使用多处理模块时,我偶然发现了一个奇怪的计时问题。
请考虑以下情形。我有这样的功能:
import multiprocessing as mp
def workerfunc(x):
# timehook 3
# something with x
# timehook 4
def outer():
# do something
mygen = ... (some generator expression)
pool = mp.Pool(processes=8)
# time hook 1
result = [pool.apply(workerfunc, args=(x,)) for x in mygen]
# time hook 2
if __name__ == '__main__':
outer()
我正在利用时间模块对函数运行多长时间有任意感觉。我成功创建了8个独立的进程,这些进程无错误终止。工人完成作业的最长时间约为130毫秒(在时间钩3和4之间测得)。
我期望(因为它们并行运行)挂钩1和挂钩2之间的时间大约相同。令人惊讶的是,结果是600毫秒。
我的机器有32个内核,应该能够轻松处理。谁能给我提示时间差异的来源?
谢谢!
答案 0 :(得分:1)
由于您使用的是多处理而不是多线程,因此性能问题与GIL(Python的全局解释器锁)无关。
我找到了一个有趣的链接,并通过示例进行了说明,您可以在此答案的底部找到它。
GIL不会阻止进程在其他进程上运行 机器的处理器。它只允许一个线程在 一次进入解释器。
因此,多处理而非多线程将使您实现真正的 并发。
让我们通过一些基准测试了解这一切,因为只有这样 将使您相信上面所说的。是的,那应该是 学习方式-体验体验,而不是仅仅阅读或 理解。因为如果您经历过一些事情, 论点可以说服您反对的想法。
var users: [User]! = [User]()
override func viewDidLoad() {
super.viewDidLoad()
Alamofire.request(url2).responseJSON { response in
switch response.result {
case .success(let value):
guard let jsonArray = value as? [[String: Any]] else { return }
self.users = jsonArray.compactMap(User.init)
print(self.users!) // works
// call function here!
self.usersLoaded()
case .failure(let error):
print(error)
}
}
}
func usersLoaded() {
print(users!)
}
其他信息
Here,您可以找到此信息的来源以及更详细的技术说明(奖金:其中还有Guido Van Rossum的引文:))
答案 1 :(得分:1)
您正在使用pool.apply
阻止了此操作。改用pool.apply_async
,然后函数调用将全部并行运行,并且每个函数调用将立即返回AsyncResult
对象。您可以使用此对象检查处理过程何时完成,然后也可以使用此对象检索结果。