使用 Python 3 在后台线程中加载数据

Load data in background thread with Python 3

无法解决这个看似简单的问题,我有点沮丧:

我有一个函数需要一些时间来加载数据:

def import_data(id):
    time.sleep(5)
    return 'data' + str(id)

一个DataModelclass调用这个函数,管理两个数据集。

class DataModel():
    def __init__(self):
        self._data_1 = import_data(1)
        self._data_2 = import_data(2)

    def retrieve_data_1(self):
        return self._data_1

    def retrieve_data_2(self):
        return self._data_2

现在,主要 UI 创建 DataModel,调用两个 import_data 函数,这会阻止它。

def main_ui():
    # This takes 5 seconds for each dataset and blocks the main UI thread
    dm = DataModel()

    # Other stuff is happening. This time could be used to load data in the background
    time.sleep(2)

    # Retrieve the first dataset
    data_1 = dm.retrieve_data_1()

    # User interaction. This time could be used to load even larger datasets
    time.sleep(10)

    # Retrieve the second dataset
    data_2 = dm.retrieve_data_2()

我希望在后台加载数据集以减少 UI 被阻止的时间。 我的想法是像这样实现它 pseudocode:

class DataModel():
    def __init__(self):
        self._data_1 = Thread(import_data(1)).start()
        self._data_2 = Thread(import_data(2)).start()

    def retrieve_data_1(self):
        return self._data_1.wait_for_result()

    def retrieve_data_2(self):
        return self._data_2.wait_for_result()

import_data 函数在单独的线程和 return Future 对象中调用。 retrieve_data 函数要么阻塞主线程等待 Future 求值,要么立即 return 其结果。

在 Python 3.x 和 threading and/or asyncio 中有没有一种简单的方法来实现这个?提前致谢!

(编辑:语法更正)

使用专为这种用途设计的 concurrent.futures 模块:

_pool = concurrent.futures.ThreadPoolExecutor()

class DataModel():
    def __init__(self):
        self._data_1 = _pool.submit(import_data, 1)
        self._data_2 = _pool.submit(import_data, 2)

    def retrieve_data_1(self):
        return self._data_1.result()

    def retrieve_data_2(self):
        return self._data_2.result()

如果您的函数是全局的,并且您的数据是可序列化的,您甚至可以从 ThreadPoolExecutor 无缝切换到 ProcessPoolExecutor 并受益于真正的 (process-based) 并行性。