Apache Beam:Python SDK中的等效DoFn.Setup

时间:2018-10-28 17:40:32

标签: google-cloud-dataflow apache-beam

在Beam Python DoFn中进行昂贵的一次性初始化的推荐方法是什么? Java SDK具有DoFn.Setup,但在Beam Python中似乎没有等效物。

当前是在DoFn初始化程序中访问attach objects to threading.local()的最佳方法吗?

3 个答案:

答案 0 :(得分:7)

数据流Python对于初始化昂贵对象的最佳方法并不是特别透明。有几种机制可以不频繁地实例化对象(目前不理想的是仅执行一次初始化)。以下概述了我进行的一些实验和得出的结论。希望Beam社区的任何人都能在我流浪的地方帮助我。

__init__

尽管__init__方法只能用于一次初始化一个昂贵的对象,但是在Worker机器上不会发生这种初始化。该对象将需要序列化才能发送给Worker,对于大型对象以及Tensorflow模型,Worker可能非常笨拙或根本无法工作。此外,由于此对象将被串行化并通过电线发送,因此在此处执行初始化并不安全,因为可以拦截有效载荷。建议不要使用此方法。

start_bundle()

数据流以离散的组处理数据,该组称为捆绑。这些在批处理过程中已经很好地定义,但是在流传输中,它们取决于吞吐量。没有用于配置Dataflow如何创建其捆绑包的机制,实际上捆绑包的大小完全由Dataflow决定。 start_bundle()方法将在Worker上调用,并可用于初始化状态,但是实验发现,在流式上下文中,此方法的调用频率比期望的要高,并且昂贵的重新初始化将经常发生。

延迟初始化

Beam的文档提出了这种方法,这出人意料地是性能最高的。延迟初始化意味着您创建一些要初始化为None的有状态参数,然后执行如下代码:

if self.expensive_object is None:
    self.expensive_object = self.__expensive_initialization()

您可以直接在process()方法中执行此代码。您还可以轻松地将依赖于global状态的一些辅助函数放在一起,以便您可以使用诸如此类的功能(该示例的示例在本文的底部):

self.expensive_object = get_or_initialize_global(‘expensive_object’, self.__expensive_initialization)

实验

以下实验是在使用上述start_bundle和惰性初始化方法配置的作业上进行的,并带有适当的日志记录以指示调用。将各种吞吐量发布到适当的队列中,并相应地记录结果。

在100秒钟内以1 msg / sec的速率传输:

Context                              Number of Invocations 
------------------------------------------------------------ 
NEW BUNDLE                                             100 
LAZY INITIALIZATION                                     25 
TOTAL MESSAGES                                         100 

在100秒内以10 msg / sec的速度

Context                              Number of Invocations 
------------------------------------------------------------ 
NEW BUNDLE                                             942 
LAZY INITIALIZATION                                      3 
TOTAL MESSAGES                                        1000 

在100秒内以100毫秒/秒的速度

Context                              Number of Invocations 
------------------------------------------------------------ 
NEW BUNDLE                                            2447 
LAZY INITIALIZATION                                     30 
TOTAL MESSAGES                                       10000 

在100秒内以1000毫秒/秒的速度

Context                              Number of Invocations 
------------------------------------------------------------ 
NEW BUNDLE                                            2293 
LAZY INITIALIZATION                                     36 
TOTAL MESSAGES                                      100000 

要点

尽管start_bundle对于高吞吐量非常有效,但是无论吞吐量如何,延迟初始化在很大程度上都是最有效的。建议在Python Beam上执行昂贵的初始化的方法。鉴于官方文档中的这句话,这个结果也许并不令人惊讶:

  

设置-在每个DoFn实例之前调用一次; Python SDK尚未实现此功能,因此用户仅可以通过延迟初始化来解决

被称为“变通”的事实并不特别令人鼓舞,也许我们可以在不久的将来看到更强大的东西。

代码示例

由Andreas Jansson提供:

def get_or_initialize_global(object_key, initialize_expensive_object):
    if object_key in globals():
        expensive_object = globals()[object_key]
    else:
        expensive_object = initialize_expensive_object()
        globals()[object_key] = expensive_object

答案 1 :(得分:1)

设置和拆卸现已成为added to the Python SDK,是在Beam Python DoFn中进行昂贵的一次性一次性初始化的推荐方法。

答案 2 :(得分:0)