3

I am using a commercial application called Abaqus/CAE1 with a built-in Python 2.6 interpreter and API. I've developed a long-running script that I'm attempting to split into simultaneous, independent tasks using Python's multiprocessing module. However, once spawned the processes just hang.

The script itself uses various objects/methods available only through Abaqus's proprietary cae module, which can only be loaded by starting up the Python bundled with Abaqus/CAE first, which then executes my script with Python's execfile.

To try to get multiprocessing working, I've attempted to run a script that avoids accessing any Abaqus objects, and instead just performs a calculation and prints the result to file2. This way, I can run the same script from the regular system Python installation as well as from the Python bundled with Abaqus.

The example code below works as expected when run from the command line using either of the following:

C:\some\path>python multi.py         # <-- Using system Python
C:\some\path>abaqus python multi.py  # <-- Using Python bundled with Abaqus

This spawns the new processes, and each runs the function and writes the result to file as expected. However, when called from the Abaqus/CAE Python environment using:

abaqus cae noGUI=multi.py

Abaqus will then start up, automatically import its own proprietary modules, and then executes my file using:

execfile("multi.py", __main__.__dict__)

where the global namespace arg __main__.__dict__ is setup by Abaqus. Abaqus then checks out licenses for each process successfully, spawns the new processes, and ... and that's it. The processes are created, but they all hang and do nothing. There are no error messages.

What might be causing the hang-up, and how can I fix it? Is there an environment variable that must be set? Are there other commercial systems that use a similar procedure that I can learn from/emulate?

Note that any solution must be available in the Python 2.6 standard library.

System details: Windows 10 64-bit, Python 2.6, Abaqus/CAE 6.12 or 6.14

Example Test Script:

# multi.py
import multiprocessing
import time

def fib(n):
    a,b = 0,1
    for i in range(n):
        a, b = a+b, a
    return a

def workerfunc(num):
    fname = ''.join(('worker_', str(num), '.txt'))
    with open(fname, 'w') as f:
        f.write('Starting Worker {0}\n'.format(num))
        count = 0
        while count < 1000:  # <-- Repeat a bunch of times.
            count += 1
            a=fib(20)
        line = ''.join((str(a), '\n'))
        f.write(line)
        f.write('End Worker {0}\n'.format(num))

if __name__ == '__main__':
    jobs = []
    for i in range(2):       # <-- Setting the number of processes manually
        p = multiprocessing.Process(target=workerfunc, args=(i,))
        jobs.append(p)
        print 'starting', p
        p.start()
        print 'done starting', p
    for j in jobs:
        print 'joining', j
        j.join()
        print 'done joining', j

1A widely known finite element analysis package

2The script is a blend of a fairly standard Python function for fib(), and examples from PyMOTW

Matt P
  • 2,287
  • 1
  • 11
  • 26

2 Answers2

0

I have to write an answer as I cannot comment yet.

What I can imagine as a reason is that python multiprocessing spawns a whole new process with it's own non-shared memory. So if you create an object in your script, the start a new process, that new process contains a copy of the memory and you have two objects that can go into different directions. When something of abaqus is present in the original python process (which I suspect) that gets copied too and this copy could create such a behaviour.

As a solution I think you could extend python with C (which is capable to use multiple cores in a single process) and use threads there.

jklmnn
  • 481
  • 1
  • 5
  • 11
  • I'm certain that Abaqus is doing a great many things in the CAE kernel before executing my file. Hmmm. When it calls `execfile` it passes in a large dict of objects to populate the namespace. Is it possible this is needed? For example, copy this into each new process using the `args` argument in `multiprocessing.Process(target=..., args=...)`? – Matt P May 25 '17 at 22:13
  • It is already copied by multiprocessing. And I think this is the reason for your problems since these objects are probably not meant to be existing multiple times. – jklmnn May 25 '17 at 22:16
  • Aha, thanks, I think I understand. I'll do some more investigating but it sounds like this is uncontrollable from the user end. – Matt P May 25 '17 at 22:30
  • Well if you really need to use multiple cores, you might look into the C API linked in my answer but this requires higher effort. If you only need concurrency you could also use threads in Python. – jklmnn May 25 '17 at 22:34
  • Uncontrollable, at least from the Python side. As you mentioned, a C extension could work, and parts of my program uses this already, so that seems reasonable...although I've never tried to write a multithreaded C program and that sounds a bit terrifying. – Matt P May 25 '17 at 22:36
  • I'm trying to verify the problem you suggested with objects being copied into the new processes, but I can't seem to replicate this issue without starting up from Abaqus first, maybe because I'm on windows. I have just now found a related discussion with `os.fork()` on Linux [here](https://stackoverflow.com/questions/25477470/how-can-i-restrict-the-scope-of-a-multiprocessing-process#25477640). Is this describing the same issue? – Matt P May 25 '17 at 22:46
  • Yes this is the behaviour I meant although I'm not familiar with how exactly this is handled in Windows (they described the diffferences in the answer) and how exactly it affects abaqus. – jklmnn May 25 '17 at 23:18
  • To any interested readers, one potential problem is how Abaqus/CAE logs/records the python code for all actions, creating a .rpy ("replay") file. Or at least, I have found several sites (eg [here](https://stackoverflow.com/questions/641420/how-should-i-log-while-using-multiprocessing-in-python/894284#894284), [here](http://bugs.python.org/issue6721)) discussing the ongoing difficulty of using logging with `multiprocessing`. I'm not sure how to test if this is the actual problem here, but it seems likely. Unfortunately, there doesn't seem to be any way to disable .rpy creation. – Matt P May 26 '17 at 16:37
0

Just wanted to say that I have run into this exact issue. My solution at the current time is to compartmentalize my scripting. This may work for you if you're trying to run parameter sweeps over a given model, or run geometric variations on the same model, etc.

I first generate scripts to accomplish each portion of my modelling process:

  1. Generate input file using CAE/Python.
  2. Extract data that I want and put it in a text file.

With these created, I use text replacement to quickly generate N python scripts of each type, one for each discrete parameter set I'm interested in.

I then wrote a parallel processing tool in Python to call multiple Abaqus instances as subprocesses. This does the following:

  1. Call CAE through subprocess.call for each model generation script. The script allows you to choose how many instances to run at once to keep you from taking every license on the server.

  2. Execute the Abaqus solver for the generated models using the same, with parameters for cores per job and total number of cores used.

  3. Extract data using the same process as 1.

There is some overhead in repeatedly checking out licenses for CAE when generating the models, but in my testing it is far outweighed by the benefit of being able to generate 10+ input files simultaneously.

I can put some of the scripts up on Github if you think the process outlined above would be helpful for your application.

Cheers, Nathan

  • Thanks, your offer to put the scripts up on github would be interesting. Unfortunately, though, what I'm trying to achieve is somewhat different - rather than many independent jobs running simultaneously, I want many "workers" attacking the same time-consuming task, splitting it up into chunks. Do you think subprocess would handle that through the Python instance started via the `abaqus cae noGUI` option? – Matt P Sep 27 '17 at 20:05
  • I don't think so, subprocess is only useful for launching outside applications that are separate from the original process. – EngineerNate Sep 27 '17 at 22:09
  • @EngineerNate Do I understand you correctly that you are running several Abaqus CAE instances/processes in parallel with the ´subprocess´ method from a separate Python script, which is run from CMD by "python YourScript.py" command? – Mike Jul 16 '20 at 11:33