https://gist.github.com/kingmo888/be4d2dfa033cd50c7bca01db70196ee2
上述是正常的代码, 如果将"f = open('test.txt', 'a')"转移到"if name == 'main':"下面后,
并且通过参数传入到函数中时,代码就运行不正常了。请问这是什么原因?
还有一个问题,为何多进程下"print('main...') "会执行了 N 次?
谢谢。
1
ltux 2017-05-09 17:35:38 +08:00
第一个问题无法回答。你需要给出你将"f = open('test.txt', 'a')"转移到"if name == 'main':"下面后,并且通过参数传入到函数中时”的具体代码,别人才能解答。仅凭几句描述不知道你都改了什么地方。
第二个问题:因为每个进程都要导入 main 模块,这就导致每个进程当中 global scope 的代码都会被执行一次。所以最好只在 global scope 放一些函数定义,其他代码比如 print 就不要放到 global scope 了。另外,在执行 global scope 的代码之前,python 解释器会设置一些特殊变量,比如 __name__。如果当前程序是做为主程序运行的,则将 __name__ 设置为 '__main__'。如果当前程序是 multiprocessing 派生出的子进程,则 __name__ 设置为 '__mp_main__'。你可以打印每个进程的 __name__ 来验证这一说法。 |
2
ltux 2017-05-09 18:06:07 +08:00
想起来一个问题。貌似传给 multiprocessing.Process 构造函数的参数必须是 pickable 的,而文件对象不是 pickable 的,你第一个问题有可能出在这儿了。
|
3
dqw 2017-05-09 19:41:56 +08:00
执行多次可能是多进程脚本被加载了多次吧,你验证一下。
|
4
dqw 2017-05-09 19:52:09 +08:00
在 print('main')下面把 pid 打印出来,每次都不一样,每个进程会都加载一次脚本,启动进程数量为进程池数量+2。自身算一个,还有一个不知道是啥。
|
5
kingmo888 OP @ltux 感谢,我表述有问题。直接上代码
https://gist.github.com/kingmo888/a7cdc36f77397f65ac19fb49f5795814 这种情况下,不会写入任何东西。 |
6
kingmo888 OP @dqw 是的。我验证了这个问题。还有一个问题,请看这段代码:
``` import pandas as pd import os, time import multiprocessing import numpy as np class Mutilprocess_Test: def __init__(self): print('init:',os.getpid()) def run(self,i): timesleep = np.random.rand()/3 #print() time.sleep(timesleep) print(i, 'run:', os.getpid(), timesleep) if __name__ == '__main__': pool = multiprocessing.Pool(processes=3) for i in range(10): pool.apply_async(Mutilprocess_Test().run, args=(i,)) pool.close() pool.join() ``` 这段代码中,类初始化时候的 pid 和 run 时候的 pid 不一样。 貌似 init 时的 pid 是主进程的。请问这是什么原因或者说应该怎样去理解呢?比如多进程运行不同的类——可能基类是一个,派生类不同,这时候如何对一些数据库连接、相同部分的数据调用的代码进行存放呢,是放到 init 中,还是放到 run 里各自取? 二者的区别会否导致数据都到各自进程下? 比如说,我有一个字典 d1,实际上所有子类都有用到这个字典 d1,这时候我把他放 main 进程中好,还是在 init 中初始化好,还是在 run 中好呢? |
7
dqw 2017-05-10 13:13:24 +08:00
貌似 init 时的 pid 是主进程的。请问这是什么原因或者说应该怎样去理解呢?
这是因为你调用 Mutilprocess_Test()是在主线程中调用的,所以 init 的 pid 是主线程。 你传入 Mutilprocess_Test().run 进去在其他进程里面执行的时候 self 参数是不是就丢掉了,你验证一下看看还能不能获取到 self。 如果你需要共享数据的话为啥不用多线程?多进程就不要考虑共享数据的事情了吧。 |
8
kingmo888 OP @dqw 多线程是不是在一个进程之下了?我的需求是有大量的数据需要计算,同时数据还很多(几十 G ),需要迭代计算的。所以运算次数相当之多。
这种情况下,用多线程可以吗? 为了解决 I/O 以及计算耗时问题,已经买了一个带 SSD 的 24 核塔式服务器。 |
9
kingmo888 OP @dqw
您看,我的需求是这样的: 数据已经按照类别放到了多个 HDF5 里,其中某个文件是 30G 左右( d1.h5 ),其中 d1 里面有 5000 多个 table。 计算逻辑: 一个基类,按照不同的需求分为 N 个子类。 之前是这样的:每一个子类读取 d1.h5,循环读取所有 table,然后计算。 哪种方式更合理呢?谢谢。 |
12
kingmo888 OP @dqw 感谢。打印 self.__name__失败,情形是子进程 while True 下,主进程都结束了。说明打印失败了。。原因是?
|
13
dqw 2017-05-10 20:08:10 +08:00
@kingmo888 原因是 python 里面的面向对象实际上是通过语法糖实现的,你传入一个 obj.func 实际上传入的只是一个函数,其第一个参数是 self,python 里面调用 obj.func()实际上是类似于:
f = obj.func f(obj) 你直接传方法进去,self 已经丢失了,因为在子进程中调用的时候不是通过对象实例调用的。 |
14
dqw 2017-05-10 20:09:14 +08:00
|
15
kingmo888 OP @dqw 您好,您说的有道理。我做了这样一个测试:
在类 Test 中某个函数比如 mutil_test 内部实现多线程,如果直接在 Test().mutil_test()这种形式,多进程的子函数执行成功。如果把 mutil_test 放到类函数 run 下,执行 Test().run()就无法执行 mutil_test 中多进程调用的子函数。 另外,多进程中无法获取到__name__,但如果我在 init 阶段,复制 self.var1=123123,然后在子函数中打印的话,可以打印出来。 |