Python 3: Catching warnings during multiprocessing

后端 未结 3 1159
醉话见心
醉话见心 2021-01-03 19:54

Too long; didn\'t read

The warnings.catch_warnings() context manager is not thread safe. How do I use it in a parallel processing environment?

Background<

3条回答
  •  Happy的楠姐
    2021-01-03 20:04

    The unpickling would not cause the __init__ to be executed twice. I ran the following code on Windows, and it doesn't happen (each __init__ is run precisely once).

    Therefore, you need to provide us with the code from my_load_balancer and from widgets' class. At this point, your question simply doesn't provide enough information.

    As a random guess, you might check whether my_load_balancer makes copies of widgets, causing them to be instantiated once again.

    import multiprocessing
    import collections
    
    "Call `frobnicate(list_of_widgets)` to get the widget with the most frobnals"
    
    def my_load_balancer(widgets):
        partitions = tuple(set() for _ in range(8))
        for i, widget in enumerate(widgets):
            partitions[i % 8].add(widget)
        for partition in partitions:
            yield partition
    
    def my_frobnal_counter(widget):
        return widget.id
    
    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)
    
    class Widget:
        id = 0
        def __init__(self):
            print('initializing Widget {}'.format(self.id))
            self.id = Widget.id
            Widget.id += 1
    
        def __str__(self):
            return str(self.id)
    
        def __repr__(self):
            return str(self)
    
    def main():
    
        widgets = [Widget() for _ in range(16)]
        result = frobnicate_parallel(widgets)
        print(result.id)
    
    
    if __name__ == '__main__':
        main()
    

提交回复
热议问题