2016-05-18 3 views
1

У меня есть приложение web2py, которое в основном служит интерфейсом браузера для скрипта Python. Этот скрипт обычно возвращается довольно быстро, но иногда может занять много времени. Я хочу предоставить пользователю возможность остановить выполнение скрипта, если он занимает слишком много времени.Остановить длительное действие в web2py с многопроцессорной обработкой

я в настоящее время вызова функции вроде этого:

def myView(): # this function is called from ajax 
    session.model = myFunc() # myFunc is from a module which i have complete control over 
    return dict(model=session.model) 

myFunc, при вызове с определенными параметрами, использует многопроцессорность, но по-прежнему заканчивается занимает много времени. Мне нужно каким-то образом закончить функцию или, по крайней мере, детей потока.

Первая вещь, которую я попытался было бежать myFunc в новом процессе, и свернуть свою собственную систему просто событие, чтобы убить его:

# in the controller 
def myView(): 
    p_conn, c_conn = multiprocessing.Pipe() 
    events = multiprocessing.Manager().dict() 
    proc = multiprocessing.Process(target=_fit, args=(options, events c_conn)) 
    proc.start() 
    sleep(0.01) 
    session.events = events 
    proc.join() 
    session.model = p_conn.recv() 
    return dict(model=session.model) 

def _fit(options, events pipe): 
    pipe.send(fitting.logistic_fit(options=options, events=events)) 
    pipe.close() 

def stop(): 
    try: 
     session.events['kill']() 
    except SystemExit: 
     pass # because it raises that error intentionally 
    return dict() 

# in the module 
def kill(): 
    print multiprocessing.active_children() 
    for p in multiprocessing.active_children(): 
     p.terminate() 
    raise SystemExit 

def myFunc(options, events): 
    events['kill'] = kill 

Я столкнулся несколько основных проблем, связанных с этим.

  1. Сессия в stop() не всегда была такой же, как сессии в myView(), поэтому session.events не было.
  2. Даже когда сессия была такой же, kill() не убивал детей.
  3. Долгосрочная функция зависает потоком web2py, поэтому stop() даже не обрабатывался до завершения функции.

Я считал не называя join() и использованием AJAX, чтобы забрать результат функции в более позднее время, но я не был в состоянии сохранить объект процесса в session для последующего использования. Казалось, что труба может быть маринована, но тогда у меня возникла проблема с невозможностью получить доступ к той же сессии из другого представления.

Как я могу реализовать эту функцию?

ответ

1

Для долговременных задач вам лучше провести их в очереди через встроенный scheduler. Если вы хотите разрешить пользователю вручную остановить слишком длительную задачу, вы можете использовать метод scheduler.stop_task(ref) (где ref - это задача id или uuid). Кроме того, когда вы ставите в очередь задачу, вы можете указать тайм-аут, поэтому он будет автоматически остановлен, если не будет завершен в течение периода ожидания.

Вы можете сделать простой опрос Ajax, чтобы уведомить клиента о завершении задачи (или реализовать что-то более сложное с помощью websockets или SSE).

+0

Не могли бы вы рассказать о своем ответе? Некоторые конкретные вещи, на которые стоит ответить: запускает ли планировщик сразу же из сценария? Как получить результат задания? Как принудительно остановить задачу? Как бы то ни было, это не полностью отвечает на вопрос. – Scimonster

+0

Я обновил ответ, чтобы ответить на ваш последний вопрос. Ваши первые два вопроса рассматриваются в связанной документации. Поскольку они связаны с общей функциональностью планировщика и не являются частью вашего первоначального вопроса, я не буду обновлять ответ, но я вкратце упомянул, что по умолчанию новые задачи ставятся в очередь сразу (и вы можете заставить работника немедленно проверить очередь, установив 'instant = True'), а метод' scheduler.task_status() 'используется для получения результатов. – Anthony