Меня вдохновил ответ Даниэля Г. и я реализовал очень простой вариант использования - в моей работе мне часто приходится повторять вызовы одного и того же (внешнего) процесса с разными аргументами. Я взломал способ определения того, когда был сделан каждый конкретный вызов, но теперь у меня есть более чистый способ создания обратных вызовов.
Мне нравится эта реализация, потому что она очень проста, но она позволяет мне выполнять асинхронные вызовы для нескольких процессоров (обратите внимание, что я использую multiprocessing
вместо threading
) и получать уведомление по завершении.
Я протестировал образец программы и прекрасно работает. Пожалуйста, отредактируйте по желанию и предоставьте отзыв.
import multiprocessing
import subprocess
class Process(object):
"""This class spawns a subprocess asynchronously and calls a
`callback` upon completion; it is not meant to be instantiated
directly (derived classes are called instead)"""
def __call__(self, *args):
# store the arguments for later retrieval
self.args = args
# define the target function to be called by
# `multiprocessing.Process`
def target():
cmd = [self.command] + [str(arg) for arg in self.args]
process = subprocess.Popen(cmd)
# the `multiprocessing.Process` process will wait until
# the call to the `subprocess.Popen` object is completed
process.wait()
# upon completion, call `callback`
return self.callback()
mp_process = multiprocessing.Process(target=target)
# this call issues the call to `target`, but returns immediately
mp_process.start()
return mp_process
if __name__ == "__main__":
def squeal(who):
"""this serves as the callback function; its argument is the
instance of a subclass of Process making the call"""
print "finished %s calling %s with arguments %s" % (
who.__class__.__name__, who.command, who.args)
class Sleeper(Process):
"""Sample implementation of an asynchronous process - define
the command name (available in the system path) and a callback
function (previously defined)"""
command = "./sleeper"
callback = squeal
# create an instance to Sleeper - this is the Process object that
# can be called repeatedly in an asynchronous manner
sleeper_run = Sleeper()
# spawn three sleeper runs with different arguments
sleeper_run(5)
sleeper_run(2)
sleeper_run(1)
# the user should see the following message immediately (even
# though the Sleeper calls are not done yet)
print "program continued"
Пример вывода:
program continued
finished Sleeper calling ./sleeper with arguments (1,)
finished Sleeper calling ./sleeper with arguments (2,)
finished Sleeper calling ./sleeper with arguments (5,)
Ниже приведен исходный код sleeper.c
- моего примера "трудоемкого" внешнего процесса
#include<stdlib.h>
#include<unistd.h>
int main(int argc, char *argv[]){
unsigned int t = atoi(argv[1]);
sleep(t);
return EXIT_SUCCESS;
}
скомпилировать как:
gcc -o sleeper sleeper.c