基于Python实现MapReduce
一、什么是MapReduce
首先,将这个单词分解为Map、Reduce。
- Map阶段:在这个阶段,输入数据集被分割成小块,并由多个Map任务处理。每个Map任务将输入数据映射为一系列(key, value)对,并生成中间结果。
- Reduce阶段:在这个阶段,中间结果被重新分组和排序,以便相同key的中间结果被传递到同一个Reduce任务。每个Reduce任务将具有相同key的中间结果合并、计算,并生成最终的输出。
举个例子,在一个很长的字符串中统计某个字符出现的次数。
from collections import defaultdict
def mapper(word):
return word, 1
def reducer(key_value_pair):
key, values = key_value_pair
return key, sum(values)
def map_reduce_function(input_list, mapper, reducer):
'''
- input_list: 字符列表
- mapper: 映射函数,将输入列表中的每个元素映射到一个键值对
- reducer: 聚合函数,将映射结果中的每个键值对聚合到一个键值对
- return: 聚合结果
'''
map_results = map(mapper, input_list)
shuffler = defaultdict(list)
for key, value in map_results:
shuffler[key].append(value)
return map(reducer, shuffler.items())
if __name__ == "__main__":
words = "python best language".split(" ")
result = list(map_reduce_function(words, mapper, reducer))
print(result)
输出结果为
[('python', 1), ('best', 1), ('language', 1)]
但是这里并没有体现出MapReduce的特点。只是展示了MapReduce的运行原理。
二、基于多线程实现MapReduce
from collections import defaultdict
import threading
class MapReduceThread(threading.Thread):
def __init__(self, input_list, mapper, shuffler):
super(MapReduceThread, self).__init__()
self.input_list = input_list
self.mapper = mapper
self.shuffler = shuffler
def run(self):
map_results = map(self.mapper, self.input_list)
for key, value in map_results:
self.shuffler[key].append(value)
def reducer(key_value_pair):
key, values = key_value_pair
return key, sum(values)
def mapper(word):
return word, 1
def map_reduce_function(input_list, num_threads):
shuffler = defaultdict(list)
threads = []
chunk_size = len(input_list) // num_threads
for i in range(0, len(input_list), chunk_size):
chunk = input_list[i:i+chunk_size]
thread = MapReduceThread(chunk, mapper, shuffler)
thread.start()
threads.append(thread)
for thread in threads:
thread.join()
return map(reducer, shuffler.items())
if __name__ == "__main__":
words = "python is the best language for programming and python is easy to learn".split(" ")
result = list(map_reduce_function(words, num_threads=4))
for i in result:
print(i)
这里的本质一模一样,将字符串分割为四份,并且分发这四个字符串到不同的线程执行,最后将执行结果归约。只不过由于Python的GIL机制,导致Python中的线程是并发执行的,而不能实现并行,所以在python中使用线程来实现MapReduce是不合理的。(GIL机制:抢占式线程,不能在同一时间运行多个线程)。
三、基于多进程实现MapReduce
由于Python中GIL机制的存在,无法实现真正的并行。这里有两种解决方案,一种是使用其他语言,例如C语言,这里我们不考虑;另一种就是利用多核,CPU的多任务处理能力。
from collections import defaultdict
import multiprocessing
def mapper(chunk):
word_count = defaultdict(int)
for word in chunk.split():
word_count[word] += 1
return word_count
def reducer(word_counts):
result = defaultdict(int)
for word_count in word_counts:
for word, count in word_count.items():
result[word] += count
return result
def chunks(lst, n):
for i in range(0, len(lst), n):
yield lst[i:i + n]
def map_reduce_function(text, num_processes):
chunk_size = (len(text) + num_processes - 1) // num_processes
chunks_list = list(chunks(text, chunk_size))
with multiprocessing.Pool(processes=num_processes) as pool:
word_counts = pool.map(mapper, chunks_list)
result = reducer(word_counts)
return result
if __name__ == "__main__":
text = "python is the best language for programming and python is easy to learn"
num_processes = 4
result = map_reduce_function(text, num_processes)
for i in result:
print(i, result[i])
这里使用多进程来实现MapReduce,这里就是真正意义上的并行,依然是将数据切分,采用并行处理这些数据,这样才可以体现出MapReduce的高效特点。但是在这个例子中可能看不出来很大的差异,因为数据量太小。在实际应用中,如果数据集太小,是不适用的,可能无法带来任何收益,甚至产生更大的开销导致性能的下降。
四、在100GB的文件中检索数据
这里依然使用MapReduce的思想,但是有两个问题
- 文件太大,读取速度慢
解决方法:
使用分块读取,但是在分区时不宜过小。因为在创建分区时会被序列化到进程,在进程中又需要将其解开,这样反复的序列化和反序列化会占用大量时间。不宜过大,因为这样创建的进程会变少,可能无法充分利用CPU的多核能力。
- 文件太大,内存消耗特别大
解决方法:
使用生成器和迭代器,但需获取。例如分块为8块,生成器会一次读取一块的内容并且返回对应的迭代器,以此类推,这样就避免了读取内存过大的问题。
from datetime import datetime
import multiprocessing
def chunked_file_reader(file_path:str, chunk_size:int):
"""
生成器函数:分块读取文件内容
- file_path: 文件路径
- chunk_size: 块大小,默认为1MB
"""
with open(file_path, 'r', encoding='utf-8') as file:
while True:
chunk = file.read(chunk_size)
if not chunk:
break
yield chunk
def search_in_chunk(chunk:str, keyword:str):
"""在文件块中搜索关键字
- chunk: 文件块
- keyword: 要搜索的关键字
"""
lines = chunk.split('\n')
for line in lines:
if keyword in line:
print(f"找到了:", line)
def search_in_file(file_path:str, keyword:str, chunk_size=1024*1024):
"""在文件中搜索关键字
file_path: 文件路径
keyword: 要搜索的关键字
chunk_size: 文件块大小,为1MB
"""
with multiprocessing.Pool() as pool:
for chunk in chunked_file_reader(file_path, chunk_size):
pool.apply_async(search_in_chunk, args=(chunk, keyword))
if __name__ == "__main__":
start = datetime.now()
file_path = "file.txt"
keyword = "张三"
search_in_file(file_path, keyword)
end = datetime.now()
print(f"搜索完成,耗时 {end - start}")
最后程序运行时间为两分钟左右。
基于Python实现MapReduce的更多相关文章
- 【Machine Learning】决策树案例:基于python的商品购买能力预测系统
决策树在商品购买能力预测案例中的算法实现 作者:白宁超 2016年12月24日22:05:42 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现的深入理解.本 ...
- 基于Python+Django的Kubernetes集群管理平台
➠更多技术干货请戳:听云博客 时至今日,接触kubernetes也有一段时间了,而我们的大部分业务也已经稳定地运行在不同规模的kubernetes集群上,不得不说,无论是从应用部署.迭代,还是从资源调 ...
- 关于《selenium2自动测试实战--基于Python语言》
关于本书的类型: 首先在我看来技术书分为两类,一类是“思想”,一类是“操作手册”. 对于思想类的书,一般作者有很多年经验积累,这类书需要细读与品位.高手读了会深有体会,豁然开朗.新手读了不止所云,甚至 ...
- psutil一个基于python的跨平台系统信息跟踪模块
受益于这个模块的帮助,在这里我推荐一手. https://pythonhosted.org/psutil/#processes psutil是一个基于python的跨平台系统信息监视模块.在pytho ...
- 一次完整的自动化登录测试-基于python+selenium进行cnblog的自动化登录测试
Web登录测试是很常见的测试!手动测试大家再熟悉不过了,那如何进行自动化登录测试呢!本文作者就用python+selenium结合unittest单元测试框架来进行一次简单但比较完整的cnblog自动 ...
- 搭建基于python +opencv+Beautifulsoup+Neurolab机器学习平台
搭建基于python +opencv+Beautifulsoup+Neurolab机器学习平台 By 子敬叔叔 最近在学习麦好的<机器学习实践指南案例应用解析第二版>,在安装学习环境的时候 ...
- 《Selenium2自动化测试实战--基于Python语言》 --即将面市
发展历程: <selenium_webdriver(python)第一版> 将本博客中的这个系列整理为pdf文档,免费. <selenium_webdriver(python)第 ...
- 从Theano到Lasagne:基于Python的深度学习的框架和库
从Theano到Lasagne:基于Python的深度学习的框架和库 摘要:最近,深度神经网络以“Deep Dreams”形式在网站中如雨后春笋般出现,或是像谷歌研究原创论文中描述的那样:Incept ...
- 基于python的互联网软件测试开发(自动化测试)-全集合
基于python的互联网软件测试开发(自动化测试)-全集合 1 关键字 为了便于搜索引擎收录本文,特别将本文的关键字给强调一下: python,互联网,自动化测试,测试开发,接口测试,服务测试,a ...
- 基于python的知乎开源爬虫 zhihu_oauth使用介绍
今天在无意之中发现了一个知乎的开源爬虫,是基于Python的,名字叫zhihu_oauth,看了一下在github上面star数还挺多的,貌似文档也挺详细的,于是就稍微研究了一下.发现果然很好用啊.就 ...
随机推荐
- char * 、BSTR、long、wchar_t *、LPCWSTR、string、QString、CStringA类型转换
char* 转 BSTR char* s1 = "zhangsan"; CString s2 = CString(s1); BSTR s3 = s2.AllocSysString( ...
- c# 解决死锁问题Monitor
前言 在高并发中,一个很关键的问题就是要避免死锁. 那么为什么会产生死锁呢?这种情况多见吗? 举一个例子: 比如方法一中先lock(object1),在lock(object1)中lock(objec ...
- 单链表之删除头结点,查找等于定值x的结点数,单链表的逆置
/* * @Author: 一届书生 * @Date: 2020-03-08 09:52:27 * @LastEditTime: 2020-03-08 13:58:30 */ #include < ...
- (react)获取json数据与传入(antd配合)
import React from 'react'; import {fetch} from 'whatwg-fetch'; // import {HashRouter as Router,Route ...
- 力扣378(java&python)-有序矩阵中第 K 小的元素(中等)
题目: 给你一个 n x n 矩阵 matrix ,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素.请注意,它是 排序后 的第 k 小元素,而不是第 k 个 不同 的元素. 你必须找到一个 ...
- 重新定义容器化 Serverless 应用的数据访问
简介: 本文首先聚焦到 AI 和大数据等应用 Serverless 化的最大挑战:计算和存储分离架构带来的数据访问延迟和远程拉取数据带宽巨大的挑战.尤其在 GPU 深度学习训练场景中,迭代式的远程读取 ...
- 阿里巴巴开源大规模稀疏模型训练/预测引擎DeepRec
简介:经历6年时间,在各团队的努力下,阿里巴巴集团大规模稀疏模型训练/预测引擎DeepRec正式对外开源,助力开发者提升稀疏模型训练性能和效果. 作者 | 烟秋 来源 | 阿里技术公众号 经历6 ...
- [JDBC] Kettle on MaxCompute 使用指南
简介: Kettle是一款开源的ETL工具,纯Java实现,可以在Windows.Unix和Linux上运行,提供图形化的操作界面,可以通过拖拽控件的方式,方便地定义数据传输的拓扑 .基本讲介绍基于K ...
- WinDbg 设置在加载到某个 DLL 进入断点
本文记录如何在 WinDbg 里,设置在加载到某个 DLL 时,自动进入断点.通过此方式用来定位是哪个业务模块加载了某个 DLL 模块 在 WinDbg 里面,可以附加到现有进程,也可以启动某个进程. ...
- Windows 对全屏应用的优化
全屏应用对应的是窗口模式应用,全屏应用指的是整个屏幕都是被咱一个应用独占了,屏幕上没有显示其他的应用,此时的应用就叫全屏应用.如希沃白板这个程序.本文主要告诉大家从微软官方的文档以及考古了解到的 Wi ...