'Use threads to speed up slow initialization of context manager

I am consuming from a python2.7 module which I cannot easily change. This module has a factory for a class that is a context manager. This works great for managing the lifetime of the object, but initializing this class involves waiting on creation of a cloud based resource and it can take many minutes to run. Within the scope of my program I need to create two of the objects such as the following:

import immutable_module

cloud_resource_name1 = "load_ai_model"
cloud_resource_name2 = "create_input_output_model"

with immutable_module.create_remote_cloud_resource(cloud_resource_name1) as a, \
     immutable_module.create_remote_cloud_resource(cloud_resource_name2) as b: 
    result = __do_imporant_thing(a, b)

print(result)

Is there a way call these two contextmanagers concurrently using threads to speed up the load time?



Solution 1:[1]

After doing more research I found a solution, but it may not be the best answer. The solution relies on calling __enter__ and __exit__ manually for the contextmanager.

import immutable_module

cloud_resource_name1 = "load_ai_model"
cloud_resource_name2 = "create_input_output_model"

a_context = immutable_module.create_remote_cloud_resource(cloud_resource_name1) 
b_context = immutable_module.create_remote_cloud_resource(cloud_resource_name2)

a = None
b = None

try:
    def __set_a():
      global a
      a = a_context.__enter__()

    def __set_b():
      global b
      b = b_context.__enter__()

    a_thread = Thread(target=__set_a)
    b_thread = Thread(target=__set_b)

    a_thread.start()
    b_thread.start()

    a_thread.join()
    b_thread.join()

    result = __do_imporant_thing(a, b)

finally:
    try:
        if a is not None:
            a_context.__exit__(*sys.exc_info())
    finally:
        if b is not None:
            b_context.__exit__(*sys.exc_info())

print(result)

This is really dirty, not generic at all, and there are potential issues with exception handling, but it works.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ShadowRanger