为了账号安全,请及时绑定邮箱和手机立即绑定

利用Python实现Apache Spark中的多线程处理:超越基础

我知道菲尔,这真难 😣

🧠

「不要试图同时做几件事情。这会降低工作效率,导致错误,并妨碍创新思维。」

———— 一位 聪明的 神经科学专家

————

当然可以,去告诉你经理吧 😑。他总是让我同时处理多项任务,尽管我在所有任务上都失败了!🤕

但在数据工程的世界里,多任务处理随处可见。每当分配任务给Spark执行器时,你都能看到这一点。任务被并行执行。

说实话,其实就连Spark有时候也会应付不来多任务,因为人类总是贪心不足,总是想要更多 😒

让我们来看一个这样的例子,看看为什么Spark不能同时处理多个任务。

用例和简单方法

一个美好的早晨,你的经理 ping 你,让你数一下项目中所有表的行数。这事儿,奇怪,你现在还能说什么呢?

现在这些表格超过了10GB。让我来展示一下在这种情况下简单的处理方式:

table_paths = [  
    "dbfs:/user/hive/warehouse/t1",  # 数据库表t1的路径
    "dbfs:/user/hive/warehouse/t2",  # 数据库表t2的路径
    "dbfs:/user/hive/warehouse/sports_details",  # 体育详情表的路径
    "dbfs:/user/hive/warehouse/silvertable",  # 银色表的路径
]
    def get_count(table):  
        count = spark.read.format("delta").load(table).count()  
        return (table, count)  

    # 使用线程池的代码实现  
    result = []  
    for table in table_paths:  
        result.append(get_count(table))  

    # 创建数据帧  
    results_df = spark.createDataFrame(result, ["table_name", "row_count"])  
    results_df.display()  # 显示结果数据帧

我们在代码里都做了些什么?

  • 我们创建了一个函数,该函数读取列表中的每一个数据表
  • 该函数读取数据表,并将 {table: count} 对存储到字典中

你看出有什么问题吗?🤔其实这些表格可以并行读取,这样能加快速度。

如果加载一个表需要5分钟,用这种简单的方法,计算每个表的行数(假设共有4个表)就需要20分钟!

在Spark UI中,任务执行看起来像这样:

简单方法中的任务运行

你可以很清楚地看到,这些员工一个接一个地被处理掉。我们必须解决这个问题!!😤

另一种使用Python多线程的方法

这里的关键在于:

这些工作各自独立,可以同时进行。

不过,理想状态下,我们不能用Spark并行执行任务。这就需要根据个人喜好添加Python。

ThreadPoolExecutor 线程池执行程序详解

ThreadPoolExecutor 是 Python 的 concurrent.futures 模块中的一个高级 API,它简化了 基于线程的并行。它让你可以轻松管理线程池,并行执行任务更高效。

这类似于Spark中的任务并行处理——但说实话,没那么强大和高效。

在我们的例子中,我们不用“for 循环”(我们在简单的方法中使用过),而是使用 ThreadPoolExecutor 来并行执行每个表的 get_count 函数。

下面这是优化后的代码:

def get_count(table):  
    count = spark.read.format("delta").load(table).count()  
    return (table, count)  

# 使用 ThreadPoolExecutor 实现代码
with ThreadPoolExecutor(max_workers=4) as executor:  
    result = list(executor.map(get_count, table_paths))  

# 创建数据框
# 其中 table_paths 是表路径的列表
results_df = spark.createDataFrame(result, ["table_name", "row_count"])  
# 显示结果数据框
results_df.display()

在上面的代码片段中,我们使用了 executor.map 函数将 “get_count” 函数与 “table_paths” 列表对应起来,并行处理每个对应的元素,这样。

最后,我们将所有执行程序的结果整理成一个列表。

看看在 Spark UI 中任务运行是什么样的。

并行执行任务

超棒的吧?😉😏

我们也可以用Databricks工作流来做这个。创建一个以表名作为参数的笔记本,并行运行这个笔记本来处理多个表。但这多没意思啊!😎(这样做不仅更耗时,还更费钱)。

在很多场景中,我们需要并行执行任务。

  1. 同时从多个来源摄取数据 — 青铜层
  2. 并行执行数据聚合和计算操作 — 银层
  3. 并行执行复杂的数据验证和质量检查。
  4. 并行处理对数据子集的不同数据转换 — 银层
  5. 在不同的数据场景上运行模拟或情景分析。

在这里我想提到,通过阅读这篇[文章],我对这个话题有了理解。这篇文章很有趣!

有多种方法可以实现我们讨论的用例。但这些方法可能需要使用新的服务或工具。

为什么不先利用我们已有的资源,而不是去寻找我们还没有的。🫰

如果你们喜欢这篇博客,请给它点个赞👏,让更多的数据工程师能看到这篇博客。

谢谢你阅读! 😁😊

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消