multiprocessing.Pool can handle this. By default, the pool will create one process per CPU on your machine. Since they all will spend some time waiting on the disk to read the files, its a good way to mostly commit your machine. Its something you can tweak if either CPU usage or disk usage makes your machine unresponsive to other programs.
The pool divides work into chunks much like your example, but in the case of heavy processing on potentially variable sized files, a chunksize of 1 can avoid you wating for the tall-pole process to complete.
import multiprocessing as mp
def do_the_work(filename):
pass
master_list = [file1, file2, fil3, ...filen]
with mp.Pool() as pool:
results = pool.map(do_the_work, master_list, chunksize=1)
Answer from tdelaney on Stack Overflowarcpy - Processing multiple files simultanously using python - Geographic Information Systems Stack Exchange
python - Processing multiple data files simultaneously using multiple cores - Stack Overflow
python - parallel processing of files from a directory - Code Review Stack Exchange
Running multiple python files in parallel - Stack Overflow
I have a very large file that I need to process, and a python script that will process it. The script just loops through the lines of the file, does the calculation on each line, and prints the processed line to an output file. However, since the calculation is merely line by line I was hoping to speed this up somewhat by breaking the file into equal-sized chunks and processing the chunks in parallel. I have 12 cores on my machine.
I can think of two naive ways to do this:
-
Use a multiprocessing pool to run the script on the X chunks in parallel (I'm not very experienced with multiprocessing but I have successfully used it in the past)
-
Simply execute the script on each chunk and then background the process, until I have X jobs running in the background.
I doubt these are exactly equivalent, though, and I was wondering what the differences are and which I could expect to be faster.
If anyone could give me some advice/clarity I'd appreciate it!
Edit: I can think of better ways to do this but they would involve rewriting this old script and I'm trying to get an example project done as quickly as possible, so I'm looking for a quick and dirty parallelization of the straightforward looping code for now, and I'll refactor things later.
If you are restricted to windows you can write a DOS sript and run it in parallel as decribed parallel execution of shell processes
If can run in linux there is a procedure pretty well worked out using gnu-parallel. I did something similar for QGIS described in more detail at How to run processing commands in parallel in QGIS
Although the examples I give are for QGIS they would work in principle for arcpy in DOS too. ie If you can generate the the proces you neeed to carry out on one file as a BASH script which incorporates the file names as inputs, then you can use gnu parallel in linux or a parallel DOS script in DOS to handle the parallel work. Based on Oles answer to: parallelising-gis-operations-in-pyqgis eg:
Assuming you had a bash script which could run your "near" process as follows
my_standalone_script.py /path/to/a/point/shpfile.shp /path/to/another/point/file.shp /path/to/output/file.shp
You could install gnu parallel and run the script in parallel with:
find /path/to/point/shpfiles -type f -name *.shp | parallel my_standalone_script.py {} /path/to/another_point_file.shp /path/to-output/folder/neared_{/}.shp
As far as reasonable time is concerned gnu parallel will carry out the operation about as well as could be be achieved given any hardware limitations. You can even cluster more computers together and have them all carry out some of the solution each. (provided you can install the software required on each unit).
Esri has a useful blog post on utilizing Python's multiprocessing module. In many cases the multiprocessing module works fine with Esri's arcpy site package, mostly for embarrassingly parallel geoprocessing tasks that do not require any shared data (e.g. feature classes in a file geodatabase) among the workers.
I have run into so many problems developing arcpy based multiprocessing applications that I rarely bother any more and usually either focus on streamlining and optimizing existing code or opting for open-source multiprocessing solutions.
In any case, when using the multiprocessing module, you will need to optimize the multiprocessing on your machine as there will be a threshold where the workers max out your system resources resulting in diminishing returns.
If your file names are in a list, you could use this code:
from multiprocessing import Process
def YourCode(filename, otherdata):
# Do your stuff
if __name__ == '__main__':
#Post process files in parallel
ListOfFilenames = ['file1','file2', ..., 'file1000']
ListOfProcesses = []
Processors = 20 # n of processors you want to use
#Divide the list of files in 'n of processors' Parts
Parts = [ListOfFilenames[i:i + Processors] for i in xrange(0, len(ListOfFilenames), Processors)]
for part in Parts:
for f in part:
p = multiprocessing.Process(target=YourCode, args=(f, otherdata))
p.start()
ListOfProcesses.append(p)
for p in ListOfProcesses:
p.join()
You can process the different files in different threads or in different processes.
The good thing of python is that its framework provides tools for you to do this:
from multiprocessing import Process
def process_panda(filename):
# this function will be started in a different process
process_panda_import()
write_results()
if __name__ == '__main__':
p1 = Process(target=process_panda, args=('file1',))
# start process 1
p1.start()
p2 = Process(target=process_panda, args=('file2',))
# starts process 2
p2.start()
# waits if process 2 is finished
p2.join()
# waits if process 1 is finished
p1.join()
The program will start 2 child-processes, which can be used do process your files. Of cource you can do something similar with threads.
You can find the documentation here: https://docs.python.org/2/library/multiprocessing.html
and here:
https://pymotw.com/2/threading/
Hi, everyone!
So, I think that I'm pretty decent with Python, but I've never had any formal training/studying. And now, it is the first time I need to improve the performance of my program. My program computes a lot of different things and processing one file takes maybe 2 minutes on a decent computer.
While the complete process is pretty complex, the issue I'm facing right now is right at the start:
First, I convert a "PDB" file into a different one, calling another software with subprocess. Then, I compute several affinity maps on this new file, which are saved to a folder created for the PDB file.
The issue is that, since it is a long process, and I need to analyze multiple files, I decided to process all the files simultaneously.
For that, I do the following:
def generate_ply_file(pdbfile):
print("Processing: ", pdbfile)
subprocess.run(["python", "../src/generate_ply_surface.py", pdbfile])
if __name__ == "__main__":
pdbfiles = glob.glob("*.pdb")
num_processes = multiprocessing.cpu_count()
with multiprocessing.Pool(processes=num_processes) as pool:
pool.map(generate_ply_file, pdbfiles)At this point, I run the program, and cool, looks like it's all running at the same time. The issue is that I see some of the files being generated returning weird errors, and when I go look at the generated directories, files that should be in folder A are in folder B, and so on.
I checked for os calls changing directories and making files non-reachable or something like that but there are none, and to be honest, I do not understand how multiprocessing works so I don´t know if that is even an issue.
Finally, my questions. How to fix this? Is multiprocessing the correct way? Should I use something different? What can I do?
Thanks for any help you guys can provide!