繁体   English   中英

如何从 PySpark 中的不同线程在一个 Sparkcontext 中运行多个作业?

[英]How to run multiple jobs in one Sparkcontext from separate threads in PySpark?

从 Spark documentation about Scheduling Within an Application中了解到:

在给定的 Spark 应用程序(SparkContext 实例)中,如果多个并行作业是从不同的线程提交的,则它们可以同时运行。 在本节中,“作业”是指 Spark 操作(例如保存、收集)以及需要运行以评估该操作的任何任务。 Spark 的调度程序是完全线程安全的,并支持此用例以启用服务于多个请求的应用程序(例如,多个用户的查询)。”

我可以在 Scala 和 Java 中找到一些相同的示例代码。 有人可以举例说明如何使用 PySpark 实现这一点吗?

我遇到了同样的问题,所以我创建了一个独立的小例子。 我使用 python 的线程模块创建多个线程并同时提交多个火花作业。

请注意,默认情况下,spark 将以先进先出 (FIFO) 的方式运行作业:http: //spark.apache.org/docs/latest/job-scheduling.html#scheduling-within-an-application 在下面的示例中,我将其更改为 FAIR 调度

# Prereqs:
# set 
# spark.dynamicAllocation.enabled         true
# spark.shuffle.service.enabled           true
  spark.scheduler.mode                    FAIR
# in spark-defaults.conf

import threading
from pyspark import SparkContext, SparkConf

def task(sc, i):
  print sc.parallelize(range(i*10000)).count()

def run_multiple_jobs():
  conf = SparkConf().setMaster('local[*]').setAppName('appname')
  # Set scheduler to FAIR: http://spark.apache.org/docs/latest/job-scheduling.html#scheduling-within-an-application
  conf.set('spark.scheduler.mode', 'FAIR')
  sc = SparkContext(conf=conf)
  for i in range(4):
    t = threading.Thread(target=task, args=(sc, i))
    t.start()
    print 'spark task', i, 'has started'


run_multiple_jobs()

输出:

spark task 0 has started
spark task 1 has started
spark task 2 has started
spark task 3 has started
30000
0 
10000
20000

今天,我也在问我同样的问题。 multiprocessing 模块提供了一个ThreadPool ,它为您生成了几个线程,因此并行运行作业。 首先实例化函数,然后创建池,然后将其map到要迭代的范围内。

就我而言,我正在为不同数量的中心(超参数调整)计算这些 WSSSE 数字,以获得“良好的”k-means 聚类……就像MLSpark 文档中概述的那样。 无需进一步解释,以下是我的 IPython 工作表中的一些单元格:

from pyspark.mllib.clustering import KMeans
import numpy as np

c_points 是 12dim 数组:

>>> c_points.cache()
>>> c_points.take(3)
[array([ 1, -1,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0]),
array([-2,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0]),
array([ 7, -1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0])]

在下文中,对于每个i ,我都在计算这个 WSSSE 值并将其作为元组返回:

def error(point, clusters):
    center = clusters.centers[clusters.predict(point)]
    return np.linalg.norm(point - center)

def calc_wssse(i):
    clusters = KMeans.train(c_points, i, maxIterations=20,
        runs=20, initializationMode="random")
    WSSSE = c_points\
        .map(lambda point: error(point, clusters))\
        .reduce(lambda x, y: x + y)
    return (i, WSSSE)

这里开始有趣的部分:

from multiprocessing.pool import ThreadPool
tpool = ThreadPool(processes=4)

运行:

wssse_points = tpool.map(calc_wssse, range(1, 30))
wssse_points

给出:

[(1, 195318509740785.66),
 (2, 77539612257334.33),
 (3, 78254073754531.1),
 ...
]

ThreadPool很方便,但可能会导致意外行为。 例如,如果所有线程都使用overwrite模式将数据帧写入同一位置,那么线程是否“覆盖”彼此的文件取决于时间。 这很像“先到先得”。

通常所有线程都会同时被评估/实现,所以这个位置最终会包含来自所有线程的所有文件(就好像它们都处于append模式一样)。 但是如果某些线程有延迟,它们当然可以覆盖其他线程的文件。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM