Python多线程-阻塞主线程

本文对比了Python与Scala实现多线程的区别,指出在Python中使用多线程控制Spark任务可以防止driver内存溢出。通过Python的Threading库,每个线程提交一个Spark作业,适合于可拆分为独立任务的场景。文中提供了Python多线程及Spark任务提交的代码示例。

写在前面:

前面已经有Scala实现多线程了,那么用Python实现多线程又有什么区别和好处?

Scala里实现多线程,启的是同一个Application,计算多线程任务的task都是同时返回到driver中进行管理。而这些task的完成情况和状态管理会一直保存在driver中,直到Application结束。如果模型迭代次数很多,或者需要写循环来做多次计算时,这很容易导致driver的内存溢出。

所以,为了同时实现多线程,而又不至于让Application任务太大、task太多、driver内存溢出,使用python来控制多线程,每个线程提交一个spark任务来实现一个训练任务。

当然这适用于好拆分成多个独立任务的场景。大家自己根据实际业务场景来选择。

Scala多线程之任务的异同、同步执行实践_Toby的博客-CSDN博客

python笔记9-多线程Threading之阻塞(join)和守护线程(setDaemon) - 隔壁的王先森 - 博客园


1、python实现多线程控制代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time: 2021/9/26 12:02 
# @Author: TobyGao

import json
import urllib2
import os, sys, datetime, time
import threading
from sys import argv

# 模型训练
def train_sh(cal_date, train_codes):
    train_shell = '''sh -x run_model.sh {cal_date} {train_codes}'''.format(
        cal_date=cal_date, train_codes=train_codes)
    sys.stderr.write(train_shell)
    state = os.system(train_shell)
    if state != 0:
        sys.stderr.write("model fit failed")
    else:
        sys.stderr.write("model fit finished")


class trainThread(threading.Thread):
    def __init__(self, name, cal_date, train_codes):
        threading.Thread.__init__(self)
        self.threadName = name
        self.cal_date = cal_date
        self.train_codes = train_codes

    def run(self):
        sys.stderr.write("开始训练: " + self.threadName)
        train_sh(self.cal_date, self.train_codes)
        sys.stderr.write("结束训练: " + self.threadName)

if __name__ == '__main__':
    script, calcDate = argv

    # 1、特征
    feature_sh = '''sh -x run_train_data.sh {calcDate}'''.format(calcDate=calcDate)
    sys.stderr.write(feature_sh)
    t = os.system(feature_sh)
    if t != 0:
        sys.stderr.write("train data failed")
    else:
        sys.stderr.write("train data finished")

    #2、训练
    cateNum = 200
    batchNum = 15
    threadNum = 5
    i = 0
    while i < cateNum:
        epoch_list = []
        thread_list = []
        for(k in range(threadNum)):
            epoch_list[k] = ""
        for j in range(i, i + batchNum):
            if j < cateNum:
                k = j%threadNum
                if epoch_list[k] == "":
                    epoch_list[k] = trainCodes[j]
                else:
                    epoch_list[k] = epoch_list[k] +"," + trainCodes[j]


        for(k in range(threadNum)):
            thread_list[k] = trainThread("epoch %d"%k,calcDate,epoch_list[k])
            thread_list[k].start()
            thread_list[k].join()  

        i = i + batchNum

    sys.stderr.write("all model fit finished")

2、sh提交spark任务代码

#!/bin/sh

export SPARK_HOME=/software/XXX/spark_3.0

if [ $# -lt 2 ]; then
  echo "请添加参数 calcDate;trainCodes"
  exit 1
fi

basePath=$(cd `dirname $0`; pwd)

calcDate=`date -d "$1" +%Y-%m-%d`
trainCodes=$2
echo ${calcDate}
echo ${trainCodes}

spark-submit --class com.XX.model.runModel \
--master yarn \
--deploy-mode cluster \
--driver-memory 16G \
--conf spark.driver.maxResultSize=16G \
--driver-cores 8 \
--num-executors 100 \
--executor-cores 8 \
--executor-memory 16G \
--conf spark.dynamicAllocation.enabled=true \
--conf spark.shuffle.service.enabled=true \
--conf spark.sql.shuffle.partitions=3200 \
--conf spark.default.parallelism=3200 \
--conf spark.storage.memoryfraction=0.4 \
--conf spark.shuffle.memoryFraction=0.4 \
--conf spark.sql.hive.mergeFiles=true \
--conf spark.blacklist.enabled=true \
--conf spark.speculation=true \
--conf spark.hadoop.hive.exec.orc.split.strategy=ETL \
--name run-model \
algorithms-model.jar ${calcDate} ${trainCodes}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值