Python 3: Łapanie ostrzeżeń podczas multiprocessingu

Za długo; nie czytałem

Thewarnings.catch_warnings() Menedżer kontekstu tonie wątek bezpieczny. Jak używać go w środowisku przetwarzania równoległego?

tło

Poniższy kod rozwiązuje problem maksymalizacji przy użyciu przetwarzania równoległego w Pythoniemultiprocessing moduł. Pobiera listę (niezmiennych) widżetów, dzieli je (patrzEfektywne wieloprocesowe przetwarzanie ogromnej, brutalnej siły w Pythonie 3), znajduje maksima („finaliści”) wszystkich partycji, a następnie znajduje maksimum („mistrz”) tych „finalistów”. Jeśli poprawnie rozumiem mój własny kod (a nie byłbym tutaj, gdybym to zrobił), udostępniam pamięć wszystkim procesom potomnym, aby nadać im widgety wejściowe, imultiprocessing używa potoku na poziomie systemu operacyjnego i wytrawiania, aby wysłać finalistyczne widgety z powrotem do głównego procesu po zakończeniu pracy.

Źródło problemu

Chcę złapać zbędne ostrzeżenia widżetu spowodowane ponowną instancją widżetów po rozpakowaniu dzieje się tak, gdy widżety wychodzą z rury międzyprocesowej. Gdy wystąpią instancje widgetów, sprawdzają własne dane, wysyłając ostrzeżenia ze standardu Pythonawarnings moduł informujący użytkownika aplikacji, że widżet podejrzewa, że ​​występuje problem z danymi wejściowymi użytkownika. Ponieważ usuwanie powoduje tworzenie obiektów, moje zrozumienie kodu implikuje, że każdy obiekt widgetu jest przywracany dokładnie raz i tylko wtedy, gdy jest finalistą po wyjściu z potoku - zobacz następną sekcję, aby zobaczyć, dlaczego nie jest to poprawne .

Widgety zostały już stworzone, zanim zostały zafałszowane, więc użytkownik jest już boleśnie świadomy tego, jaki błąd popełnił i nie chce o tym słyszeć. To są ostrzeżenia, które chciałbym złapać za pomocąwarnings modułycatch_warnings() menedżer kontekstu (tj. awith komunikat).

Nieudane rozwiązania

W moich testach zawęziłem zakres, gdy nadmiarowe ostrzeżenia są emitowane w dowolne miejsce między tym, co oznaczyłem poniżejLinia A iLinia B. To, co mnie zaskakuje, to to, że ostrzeżenia są emitowane w miejscach innych niż tylko w pobliżuoutput_queue.get(). Oznacza to dla mnie tomultiprocessing wysyła widgety do pracowników za pomocą wytrawiania.

W efekcie umieszczenie menedżera kontekstu przezwarnings.catch_warnings() nawet wokół wszystkiegoLinia A doLinia B a ustawienie odpowiedniego filtru ostrzeżeń w tym kontekście nie powoduje ostrzeżenia. Oznacza to dla mnie, że ostrzeżenia są emitowane w procesach roboczych. Umieszczenie tego menedżera kontekstu wokół kodu pracownika również nie przechwytuje ostrzeżeń.

Kod

W tym przykładzie pominięto kod decydujący o tym, czy rozmiar problemu jest zbyt mały, aby zajmować się rozwidlaniem procesów, importowaniem wieloprocesorowości i definiowaniemmy_frobnal_counter, imy_load_balancer.

"Call `frobnicate(list_of_widgets)` to get the widget with the most frobnals"

def frobnicate_parallel_worker(widgets, output_queue):
    resultant_widget = max(widgets, key=my_frobnal_counter)
    output_queue.put(resultant_widget)

def frobnicate_parallel(widgets):
    output_queue = multiprocessing.Queue()
    # partitions: Generator yielding tuples of sets
    partitions = my_load_balancer(widgets)
    processes = []
    # Line A: Possible start of where the warnings are coming from.
    for partition in partitions:
        p = multiprocessing.Process(
                 target=frobnicate_parallel_worker,
                 args=(partition, output_queue))
        processes.append(p)
        p.start()
    finalists = []
    for p in processes:
        finalists.append(output_queue.get())
    # Avoid deadlocks in Unix by draining queue before joining processes
    for p in processes:
        p.join()
    # Line B: Warnings no longer possible after here.
    return max(finalists, key=my_frobnal_counter)

questionAnswers(2)

yourAnswerToTheQuestion