在同时使用结果的同时将dask数组提交给分布式客户端

时间:2019-02-05 15:05:11

标签: python dask dask-distributed

我有一个代表视频帧的dask数组,并且想要创建多个视频文件。我正在使用imageio库,该库允许我将帧“附加”到ffmpeg子进程中。所以我可能会遇到这样的事情:

my_frames = [[arr1f1, arr1f2, arr1f3], [arr2f1, arr2f2, arr2f3], ...]

因此,每个内部列表代表一个视频(或产品)的帧。我正在寻找发送/提交要计算的帧的最佳方法,同时还要在帧完成时(按顺序)将帧写入imageio。更复杂的是,上面的内部列表实际上是生成器,可以是100或1000帧。另外请记住,由于imageio的工作方式,我认为它必须存在于单个过程中。这是到目前为止我工作的简化版本:

for frame_arrays in frames_to_write:
    # 'frame_arrays' is [arr1f1, arr2f1, arr3f1, ...]
    future_list = _client.compute(frame_arrays)
    # key -> future
    future_dict = dict(zip(frame_keys, future_list))

    # write the current frame
    # future -> key
    rev_future_dict = {v: k for k, v in future_dict.items()}
    result_iter = as_completed(future_dict.values(), with_results=True)
    for future, result in result_iter:
        frame_key = rev_future_dict[future]
        # get the writer for this specific video and add a new frame
        w = writers[frame_key]
        w.append_data(result)

这有效,我的实际代码从上面进行了重组,以便在编写当前框架时提交下一框架,因此我认为有一些好处。我在考虑一种解决方案,用户说“我想一次处理X帧”,所以我发送50帧,写50帧,再发送50帧,写50帧,等等。

一段时间后我的问题:

  1. result的数据何时存储在本地内存中?何时由迭代器返回它或何时完成?
  2. 是否可以使用dask-core线程调度程序执行类似的操作,从而使用户不必安装分布式程序?
  3. 是否可以根据工作人员的数量来调整发送多少帧?
  4. 是否可以发送包含dask数组的字典和/或使用包含“ frame_key”的as_completed?
  5. 如果我加载整个框架系列并将其提交给客户端/集群,我可能会杀死调度程序,对吧?
  6. 使用get_client(),然后在Client()上使用ValueError来获得客户端(如果用户未提供)的首选方式是
  7. 是否有可能给dask / distributed一个或多个迭代器,以便在工作人员可用时从中提取?
  8. 我愚蠢吗?太复杂了吗?

注意:这是对this issue的扩展,我之前做了,但略有不同。

1 个答案:

答案 0 :(得分:0)

在遵循了许多示例here之后,我得到了以下内容:

    try:
        # python 3
        from queue import Queue
    except ImportError:
        # python 2
        from Queue import Queue
    from threading import Thread

    def load_data(frame_gen, q):
        for frame_arrays in frame_gen:
            future_list = client.compute(frame_arrays)
            for frame_key, arr_future in zip(frame_keys, future_list):
                q.put({frame_key: arr_future})
        q.put(None)

    input_q = Queue(batch_size if batch_size is not None else 1)
    load_thread = Thread(target=load_data, args=(frames_to_write, input_q,))
    remote_q = client.gather(input_q)
    load_thread.start()

    while True:
        future_dict = remote_q.get()
        if future_dict is None:
            break

        # write the current frame
        # this should only be one element in the dictionary, but this is
        # also the easiest way to get access to the data
        for frame_key, result in future_dict.items():
            # frame_key = rev_future_dict[future]
            w = writers[frame_key]
            w.append_data(result)
        input_q.task_done()

    load_thread.join()

这回答了我所遇到的大多数问题,并且似乎可以按照我希望的方式工作。