我正在尝试通过运行从我的Python应用程序启动的第三方可执行应用程序来实现简单的并行数据处理,并且遇到了一些连接并行执行的有趣问题。
用例非常简单。我有一个数据对象列表,应该通过第三方.exe文件处理。我们称之为consoleApp.exe。 应该通过调用此consoleApp来处理每个数据对象几次。 出于测试目的,此控制台应用程序只是将一些文本写入控制台,等待一秒然后退出。
这是我的Python代码,它将进行此类处理
def ProcessFile(idx, row):
config = UtilitySettings.ConfigFile + " some_arguments"
config2 = UtilitySettings.config2File + " some_arguments_2"
config3 = UtilitySettings.config3File + " some_arguments_3"
config4 = UtilitySettings.config4File + " some_arguments_4"
fullFileName = AppSettings.BinaryDataDirectory + row.FileName
cmd1 = "ConsoleApp.exe" + ' ' + fullFileName + ' ' + config
cmd2 = "ConsoleApp.exe" + ' ' + fullFileName + ' ' + config2
cmd3 = "ConsoleApp.exe" + ' ' + fullFileName + ' ' + config3
cmd4 = "ConsoleApp.exe" + ' ' + fullFileName + ' ' + config4
devnull = open(os.devnull, 'w')
call(cmd1, stdout=devnull, stderr=devnull)
call(cmd2, stdout=devnull, stderr=devnull)
call(cmd3, stdout=devnull, stderr=devnull)
下一代代码将启动并行处理:
class ConvertDataCommand(ICommand):
def Execute(self):
startExecutionTime = time.time()
result = CommandExecutionResult()
try:
geoDataFrame = geopandas.GeoDataFrame(objectInfo, crs=crs, geometry = objectInfo.geometry)
# let's use cpu count - 1 . The last one core will be used by the currently executed parent thread
coreCount = multiprocessing.cpu_count() - 1
dataFrameLength = len(geoDataFrame)
# splitting dataFrame to the chuncks to perform parallel processing
chunksCount = dataFrameLength / coreCount if dataFrameLength % coreCount == 0 else dataFrameLength / coreCount + 1
chunkedArr = np.array_split(geoDataFrame, chunksCount)
for slice in chunkedArr:
pool = multiprocessing.Pool(processes=coreCount)
results = [pool.apply(ProcessFile, args=(idx, row)) for idx, row in slice.iterrows()]
pool.close()
pool.join()
result.Success = True
except BaseException as e:
result.Success = False
stacktrace = traceback.format_exc()
Logger.Log(stacktrace)
finally:
result.ExecutionTime = time.time() - startExecutionTime
return result
主要有趣的是,在我的情况下,并行处理比按顺序处理(142秒)处理此数据需要花费更多时间(178秒)(但它不应该)。 看起来所有核心都使用了这个控制台应用程序(但我希望每个进程都会调用一个新的consoleApp.exe实例并在每个进程中执行它) 我在更改consoleApp.exe的实现时找到了它。 我只是编写一个无限循环并再次启动Python程序。 然后打开Process explorer,它只显示ConsoleApp.exe的一个实例和我的Python应用程序创建的3个进程。
有人知道我做错了什么吗?
答案 0 :(得分:0)
哦,太好了。 通过调用pool.map()函数而不是pool.apply()解决了这个问题(因为它会阻塞线程,直到结果准备好。有关详细信息,请参阅python-docs)
并从以下位置更改调用方法的签名:
def ProcessFile(idx, row):
到:
def ProcessFile(args):
idx, row = args
for slice in chunkedArr:
pool = multiprocessing.Pool(processes=coresNum)
data = [(idx, row) for idx, row in slice.iterrows()]
results = pool.map(ProcessFile, data)
pool.close()
pool.join()