web-dev-qa-db-fra.com

Comment exécuter plusieurs travaux dans un Sparkcontext à partir de threads séparés dans PySpark?

Il est compris de Spark documentation sur Planification dans une application :

Dans une application Spark (instance SparkContext) donnée, plusieurs travaux parallèles peuvent s'exécuter simultanément s'ils ont été soumis à partir de threads séparés. Par "travail", dans cette section, nous entendons un Spark (par exemple enregistrer, collecter) et toutes les tâches qui doivent être exécutées pour évaluer cette action. Le planificateur de Spark est entièrement thread-safe et prend en charge ce cas d'utilisation pour permettre aux applications qui servent plusieurs demandes (par exemple, les requêtes pour plusieurs utilisateurs) . "

J'ai pu trouver quelques exemples de code du même dans Scala et Java. Quelqu'un peut-il donner un exemple de la façon dont cela peut être mis en œuvre en utilisant PySpark?

19
Meethu Mathew

Je rencontrais le même problème, j'ai donc créé un petit exemple autonome. Je crée plusieurs threads en utilisant le module de threading de python et soumets plusieurs jobs spark simultanément).

Notez que par défaut, spark exécutera les travaux dans First-In First-Out (FIFO): http://spark.Apache.org/docs/latest/job- scheduling.html # scheduling-within-an-application . Dans l'exemple ci-dessous, je le remplace par FAIR scheduling

# 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()

Production:

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

Aujourd'hui, je me demandais la même chose. Le module de multitraitement propose un ThreadPool, qui génère quelques threads pour vous et exécute donc les travaux en parallèle. Commencez par instancier les fonctions, puis créez le pool, puis map sur la plage que vous souhaitez itérer.

Dans mon cas, je calculais ces nombres WSSSE pour différents nombres de centres (réglage d'hyperparamètre) pour obtenir un "bon" clustering k-means ... tout comme il est indiqué dans le documentation MLSpark . Sans plus d'explications, voici quelques cellules de ma feuille de calcul IPython:

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

c_points sont des tableaux 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])]

Dans ce qui suit, pour chaque i, je calcule cette valeur WSSSE et la renvoie en tant que Tuple:

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)

Ici commence la partie intéressante:

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

Exécuter:

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

donne:

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