Exception: Java gateway process exited before sending the driver its port number(以解決)附源碼

代碼如下:

#! /usr/bin/python
# -*- coding: utf8 -*-
#author:yukang
import pyspark
from pyspark import SparkContext as sc
from pyspark import SparkConf
import os

conf = SparkConf().setAppName('test').setMaster('local[*]')
sc = sc.getOrCreate(conf)

報錯如下:



解決方案:


解決方案網上找了一大推,但是都不能解決我的問題。

那麼只能自己看源碼解決了。

看報錯:

首先進入getOrCreate()方法中,這個方法是實例化一個SparkContext,並將其註冊爲singleton對象。

跳轉SparkContext()類中中,__init__初始化。

跳轉_ensure_initialized()方法中,主要檢查SparkContext是否被初始化。

最後跳轉launch_gateway()中,主要錯誤在這裏面。這裏主要啓動 jvm 網關。

首先看報錯文件的源碼,源碼我都給與了中文備註,源碼如下:

import atexit
import os
import sys
import select
import signal
import shlex
import socket
import platform
from subprocess import Popen, PIPE

if sys.version >= '3':
    xrange = range

from py4j.java_gateway import java_import, JavaGateway, GatewayClient
from pyspark.find_spark_home import _find_spark_home
from pyspark.serializers import read_int


def launch_gateway(conf=None):
    """
    launch jvm gateway
    啓動 jvm 網關
    :param conf: spark configuration passed to spark-submit
    :return:
    """
    if "PYSPARK_GATEWAY_PORT" in os.environ:
        gateway_port = int(os.environ["PYSPARK_GATEWAY_PORT"])
    else:
        SPARK_HOME = _find_spark_home()
        # Launch the Py4j gateway using Spark's run command so that we pick up the
        #使用Spark的run命令我們就可以啓動Py4j網關
        # proper classpath and settings from spark-env.sh
        # spark-env.sh 類的路徑和設置
        on_windows = platform.system() == "Windows"
        script = "./bin/spark-submit.cmd" if on_windows else "./bin/spark-submit"
        command = [os.path.join(SPARK_HOME, script)]
        if conf:
            for k, v in conf.getAll():
                command += ['--conf', '%s=%s' % (k, v)]
        submit_args = os.environ.get("PYSPARK_SUBMIT_ARGS", "pyspark-shell")
        if os.environ.get("SPARK_TESTING"):
            submit_args = ' '.join([
                "--conf spark.ui.enabled=false",
                submit_args
            ])
        command = command + shlex.split(submit_args)

        # Start a socket that will be used by PythonGatewayServer to communicate its port to us
        # 啓動一個套接字,它將由python-ongatewayserver用於將其端口與我們通信
        callback_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        callback_socket.bind(('127.0.0.1', 0))
        callback_socket.listen(1)
        callback_host, callback_port = callback_socket.getsockname()
        env = dict(os.environ)
        env['_PYSPARK_DRIVER_CALLBACK_HOST'] = callback_host
        env['_PYSPARK_DRIVER_CALLBACK_PORT'] = str(callback_port)

        # Launch the Java gateway.   啓動Java網關。
        # We open a pipe to stdin so that the Java gateway can die when the pipe is broken
        # 我們打開一個管道到stdin,這樣Java網關就會在管道被破壞時死亡
        if not on_windows:
            # Don't send ctrl-c / SIGINT to the Java gateway:
            # 不要向Java網關發送ctrl-c/SIGINT:
            def preexec_func():
                signal.signal(signal.SIGINT, signal.SIG_IGN)
            proc = Popen(command, stdin=PIPE, preexec_fn=preexec_func, env=env)
        else:
            # preexec_fn not supported on Windows
            # 在Windows上不支持preexec fn
            proc = Popen(command, stdin=PIPE, env=env)

        gateway_port = None
        # We use select() here in order to avoid blocking indefinitely if the subprocess dies
        # before connecting
        # 我們使用select()來避免在連接之前終止子進程
        while gateway_port is None and proc.poll() is None:
            timeout = 1  # (seconds)
            readable, _, _ = select.select([callback_socket], [], [], timeout)
            if callback_socket in readable:
                gateway_connection = callback_socket.accept()[0]
                # Determine which ephemeral port the server started on:
                # 確定服務器啓動的臨時窗口
                gateway_port = read_int(gateway_connection.makefile(mode="rb"))
                gateway_connection.close()
                callback_socket.close()
        if gateway_port is None:
            raise Exception("Java gateway process exited before sending the driver its port number")

        # In Windows, ensure the Java child processes do not linger after Python has exited.
        # In UNIX-based systems, the child process can kill itself on broken pipe (i.e. when
        # the parent process' stdin sends an EOF). In Windows, however, this is not possible
        # because java.lang.Process reads directly from the parent process' stdin, contending
        # with any opportunity to read an EOF from the parent. Note that this is only best
        # effort and will not take effect if the python process is violently terminated.
        if on_windows:
            # In Windows, the child process here is "spark-submit.cmd", not the JVM itself
            # (because the UNIX "exec" command is not available). This means we cannot simply
            # call proc.kill(), which kills only the "spark-submit.cmd" process but not the
            # JVMs. Instead, we use "taskkill" with the tree-kill option "/t" to terminate all
            # child processes in the tree (http://technet.microsoft.com/en-us/library/bb491009.aspx)
            def killChild():
                Popen(["cmd", "/c", "taskkill", "/f", "/t", "/pid", str(proc.pid)])
            atexit.register(killChild)

    # Connect to the gateway
    gateway = JavaGateway(GatewayClient(port=gateway_port), auto_convert=True)

    # Import the classes used by PySpark
    java_import(gateway.jvm, "org.apache.spark.SparkConf")
    java_import(gateway.jvm, "org.apache.spark.api.java.*")
    java_import(gateway.jvm, "org.apache.spark.api.python.*")
    java_import(gateway.jvm, "org.apache.spark.ml.python.*")
    java_import(gateway.jvm, "org.apache.spark.mllib.api.python.*")
    # TODO(davies): move into sql
    java_import(gateway.jvm, "org.apache.spark.sql.*")
    java_import(gateway.jvm, "org.apache.spark.sql.api.python.*")
    java_import(gateway.jvm, "org.apache.spark.sql.hive.*")
    java_import(gateway.jvm, "scala.Tuple2")

    return gateway

可以很清楚的看到報錯由 87行 自定義錯誤引發。


那麼怎麼解決。

方法:

導入os模塊,然後代碼中添加,=號後面的地址主要看你JDK的地址,按個人地址爲主,我的地址只做參考:

os.environ ['JAVA_HOME'] = 'D:\jdk1.8'


完美解決問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章