将SparkContext传递给新进程(python多处理模块)

时间:2015-09-07 17:08:30

标签: python apache-spark timeout pyspark python-multiprocessing

我正在使用Python / Spark运行一系列不同的工作,一次一个。为了避免每次创建SparkContex,这需要一段时间,我想将上下文作为参数发送到每个作业。最重要的是,我希望管理器(创建上下文并运行作业的代码)具有超时机制。

我在第一次工作时遇到一个奇怪的错误,此后它就消失了。

Traceback (most recent call last):
File "/usr/lib/python3.4/multiprocessing/process.py", line 254, in _bootstrap
    self.run()
  File "/usr/lib/python3.4/multiprocessing/process.py", line 93, in run
    self._target(*self._args, **self._kwargs)
  File "/home/dev/ComponentEngine/components/ExampleComponent/ExampleComponent.py", line 35, in run
    numbers = sparkContext.parallelize([1,2,3,4,5,6,7,8,9,10])
  File "/home/dev/Programs/spark-1.4.1-bin-hadoop2.6/python/pyspark/context.py", line 395, in parallelize
    readRDDFromFile = self._jvm.PythonRDD.readRDDFromFile
  File "/home/dev/Programs/spark-1.4.1-bin-hadoop2.6/python/lib/py4j-0.8.2.1-src.zip/py4j/java_gateway.py", line 772, in __getattr__
    raise Py4JError('{0} does not exist in the JVM'.format(name))
py4j.protocol.Py4JError: PythonRDD does not exist in the JVM

代码:

#!/bin/python3
import multiprocessing
from pyspark import SparkContext

def doJob(sc):
    try:
        sc.parallelize([1,2,3,4,5,6,7,8,9,10])
    except Exception as e:
        print('Got excpetion {}'.format(e))

def runWithTimeout(sc):
    p = multiprocessing.Process(target=doJob, name="runWithTimeout", args=(sc))
    p.start()

    # Wait till the timeout
    p.join(10)

    if p.is_alive():
        p.terminate()
        p.join()


if __name__ == '__main__':
    sc = SparkContext()
    for i in range(3):
        runWithTimeout(sc)

为什么会出现此错误?
以这种方式传递SparkContext有什么问题吗?我知道它被序列化并被另一端的进程使用。如果作业对上下文执行任何更改,则引擎的副本不会受到影响。
是否有任何此类变化会干扰其他工作的运行?

1 个答案:

答案 0 :(得分:1)

序列化Spark上下文在任何支持的语言中都不能很好地工作。通常,最新完成的是IBM Spark Kernel或ooyola jobserver,其中单个进程*持有Spark Context,多个客户端与服务器通信。在python中,Spark Context包括用于与JVM SparkContext通信的网络套接字,并且网络套接字不是真正可序列化的对象。看看py4j(Spark用来在python和JVM之间进行通信的库),多线程可以工作,因为它们可以共享套接字,但多个进程并没有那么多。