当前位置:首页 » 编程语言 » python分布式计算

python分布式计算

发布时间: 2023-09-18 05:26:08

1. python五大应用领域是什么

一、网络爬虫


网络爬虫是Python比较常用的一个场景,国际上,google在前期大量地运用Python言语作为网络爬虫的根底,带动了整个Python言语的运用发展。


二、数据处理


Python有很齐备的生态环境。"大数据"分析中涉及到的分布式核算、数据可视化、数据库操作等,Python中都有成熟的模块能够挑选完结其功能。关于Hadoop-MapRece和Spark,都能够直接运用Python完结核算逻辑,这不管关于数据科学家仍是关于数据工程师而言都是十分便当的。


三、web开发


Python的诞生前史比Web还要早,由于Python是一种解说型的脚本言语,开发效率高,所以十分适合用来做Web开发。


Django 是 Python 编程言语驱动的一个开源模型-视图-控制器(MVC)风格的 Web 运用程序结构。运用 Django,咱们在几分钟之内就能够创建高品质、易维护、数据库驱动的运用程序。


四、数据分析


关于数据分析师来说,不只要自己理解数据背面的含义,而且还要给更直地展现数据的含义。


Scipy是一组专门解决科学核算中各种规范问题域的包的集合。Numpy是python科学核算的根底包。Pandas处理上千万的数据是一挥而就的工作,同时随后咱们也将看到它比SQL有更强的表达能力,能够做很多复杂的操作,要写的code也更少。


五、人工智能


人工智能是现在十分火的一个方向,AI热潮让Python言语的未来充满了无限的潜力。现在释放出来的几个十分有影响力的AI结构,大多是Python的实现,为什么呢?


在人工智能大领域领域内的数据发掘、机器学习、神经网络、深度学习等方面都是主流的编程言语,得到广泛的支持和运用。人工智能的核心算法大部分仍是依赖于C/C++的,由于是核算密集型,需求十分精细的优化,还需求GPU、专用硬件之类的接口,这些都只要C/C++能做到。


关于Python五大应用领域是什么,环球青藤小编就和大家分享到这里了,学习是永无止境的,学习一项技能更是受益终身,所以,只要肯努力学,什么时候开始都不晚。如果您还想继续了解关于python编程的学习方法及素材等内容,可以点击本站其他文章学习。

2. python分布式爬虫是什么意思

一、分布式爬虫架构

在了解分布式爬虫架构之前,首先回顾一下Scrapy的架构,如下图所示。

我们需要做的就是在多台主机上同时运行爬虫任务协同爬取,而协同爬取的前提就是共享爬取队列。这样各台主机就不需要各自维护爬取队列,而是从共享爬取队列存取Request。但是各台主机还是有各自的Scheler和Downloader,所以调度和下载功能分别完成。如果不考虑队列存取性能消耗,爬取效率还是会成倍提高。

二、维护爬取队列

那么这个队列用什么来维护?首先需要考虑的就是性能问题。我们自然想到的是基于内存存储的Redis,它支持多种数据结构,例如列表(List)、集合(Set)、有序集合(Sorted Set)等,存取的操作也非常简单。

Redis支持的这几种数据结构存储各有优点。

  • 列表有lpush()、lpop()、rpush()、rpop()方法,我们可以用它来实现先进先出式爬取队列,也可以实现先进后出栈式爬取队列。

  • 集合的元素是无序的且不重复的,这样我们可以非常方便地实现随机排序且不重复的爬取队列。

  • 有序集合带有分数表示,而Scrapy的Request也有优先级的控制,我们可以用它来实现带优先级调度的队列。

  • 我们需要根据具体爬虫的需求来灵活选择不同的队列。

    三、如何去重

    Scrapy有自动去重,它的去重使用了Python中的集合。这个集合记录了Scrapy中每个Request的指纹,这个指纹实际上就是Request的散列值。我们可以看看Scrapy的源代码,如下所示:


    importhashlib
    defrequest_fingerprint(request, include_headers=None):
    ifinclude_headers:
    include_headers = tuple(to_bytes(h.lower())
    forhinsorted(include_headers))
    cache = _fingerprint_cache.setdefault(request, {})
    ifinclude_headersnotincache:
    fp = hashlib.sha1()
    fp.update(to_bytes(request.method))
    fp.update(to_bytes(canonicalize_url(request.url)))
    fp.update(request.bodyorb'')
    ifinclude_headers:
    forhdrininclude_headers:
    ifhdrinrequest.headers:
    fp.update(hdr)
    forvinrequest.headers.getlist(hdr):
    fp.update(v)
    cache[include_headers] = fp.hexdigest()
    returncache[include_headers]

    request_fingerprint()就是计算Request指纹的方法,其方法内部使用的是hashlib的sha1()方法。计算的字段包括Request的Method、URL、Body、Headers这几部分内容,这里只要有一点不同,那么计算的结果就不同。计算得到的结果是加密后的字符串,也就是指纹。每个Request都有独有的指纹,指纹就是一个字符串,判定字符串是否重复比判定Request对象是否重复容易得多,所以指纹可以作为判定Request是否重复的依据。

    那么我们如何判定重复呢?Scrapy是这样实现的,如下所示:


    def__init__(self):
    self.fingerprints = set()

    defrequest_seen(self, request):
    fp = self.request_fingerprint(request)
    iffpinself.fingerprints:
    returnTrue
    self.fingerprints.add(fp)

    在去重的类RFPDupeFilter中,有一个request_seen()方法,这个方法有一个参数request,它的作用就是检测该Request对象是否重复。这个方法调用request_fingerprint()获取该Request的指纹,检测这个指纹是否存在于fingerprints变量中,而fingerprints是一个集合,集合的元素都是不重复的。如果指纹存在,那么就返回True,说明该Request是重复的,否则这个指纹加入到集合中。如果下次还有相同的Request传递过来,指纹也是相同的,那么这时指纹就已经存在于集合中,Request对象就会直接判定为重复。这样去重的目的就实现了。

    Scrapy的去重过程就是,利用集合元素的不重复特性来实现Request的去重。

    对于分布式爬虫来说,我们肯定不能再用每个爬虫各自的集合来去重了。因为这样还是每个主机单独维护自己的集合,不能做到共享。多台主机如果生成了相同的Request,只能各自去重,各个主机之间就无法做到去重了。

    那么要实现去重,这个指纹集合也需要是共享的,Redis正好有集合的存储数据结构,我们可以利用Redis的集合作为指纹集合,那么这样去重集合也是利用Redis共享的。每台主机新生成Request之后,把该Request的指纹与集合比对,如果指纹已经存在,说明该Request是重复的,否则将Request的指纹加入到这个集合中即可。利用同样的原理不同的存储结构我们也实现了分布式Reqeust的去重。

    四、防止中断

    在Scrapy中,爬虫运行时的Request队列放在内存中。爬虫运行中断后,这个队列的空间就被释放,此队列就被销毁了。所以一旦爬虫运行中断,爬虫再次运行就相当于全新的爬取过程。

    要做到中断后继续爬取,我们可以将队列中的Request保存起来,下次爬取直接读取保存数据即可获取上次爬取的队列。我们在Scrapy中指定一个爬取队列的存储路径即可,这个路径使用JOB_DIR变量来标识,我们可以用如下命令来实现:


    scrapy crawl spider -s JOB_DIR=crawls/spider

    更加详细的使用方法可以参见官方文档,链接为:https://doc.scrapy.org/en/latest/topics/jobs.html。

    在Scrapy中,我们实际是把爬取队列保存到本地,第二次爬取直接读取并恢复队列即可。那么在分布式架构中我们还用担心这个问题吗?不需要。因为爬取队列本身就是用数据库保存的,如果爬虫中断了,数据库中的Request依然是存在的,下次启动就会接着上次中断的地方继续爬取。

    所以,当Redis的队列为空时,爬虫会重新爬取;当Redis的队列不为空时,爬虫便会接着上次中断之处继续爬取。

    五、架构实现

    我们接下来就需要在程序中实现这个架构了。首先实现一个共享的爬取队列,还要实现去重的功能。另外,重写一个Scheer的实现,使之可以从共享的爬取队列存取Request。

    幸运的是,已经有人实现了这些逻辑和架构,并发布成叫Scrapy-Redis的Python包。接下来,我们看看Scrapy-Redis的源码实现,以及它的详细工作原理

3. Python分布式进程中你会遇到的坑

写在前面

小惊大怪

你是不是在用Python3或者在windows系统上编程?最重要的是你对进程和线程不是很清楚?那么恭喜你,在python分布式进程中,会有坑等着你去挖。。。(hahahaha,此处允许我吓唬一下你)开玩笑的啦,不过,如果你知道序列中不支持匿名函数,那这个坑就和你say byebye了。好了话不多数,直接进入正题。

分布式进程

正如大家所知道的Process比Thread更稳定,而且Process可以分布到多台机器上,而Thread最多只能分布到同一陆坦咐台机器的多个CPU上。Python的multiprocessing模块不但支持多进程,其中managers子模块还支持把多进程分布到多台机器上。一个服务进程可以作为调度者,将任务分布到其他多个进程中,依靠网络通信。由于managers模块封装很好,不必了解网络通信的细节,就可以很容易地编写分布式多进程程序。

代码记录

举个例子

如果我们已经有一个通过Queue通信的多进程程序在同一台机器上运行,现在,由于处理任务的进程任务繁重,希望把发送任务的进程和处理任务的进程分布到两台机器上,这应该怎么用分布式进程来实现呢?你已经知道了原有的Queue可以继续使用,而且通过managers模块把Queue通过网络暴露出去,就可以让其他机器的进程来访问Queue了。好,那我们就这么干!

写个task_master.py

我们先看服务进程。服务进程负责启动Queue,把Queue注册到网络上,然后往Queue里面写入任务。

请注意,当我们在一台机器上写多进程程序时,创建的Queue可以直接拿来用,但是,在分布式多进程环境下,添加任务到Queue不可以直接对原始的task_queue进行操作,那样就绕过了QueueManager的封装,必须通过manager.get_task_queue()获得的Queue接口添加。然后,在另一台机器上启动任务进程(本机上启动也可以)

写个task_worker.py

任务进程要通过网络连接到服务进程,所以要指定服务进程的IP。

运行结果

现在,可信没以试试分布式进程的工作效果了。先启动task_master.py服务进程:

task_master.py进程发送完任务后,开始等待result队列的结果。现在启动task_worker.py进程:

看到没,结果都出错了,我们好好分析一下到底哪出错了。。。

错误分析

在task_master.py的报错提示中,我们知道它说lambda错误,这是因为序列化不支持匿名函数,所以我们得修改代码,重新对queue用QueueManager进行封装放到网络中。

其中task_queue和result_queue是两个队列,分别存放任务和结果。它们用来进行进程间通信,交换对象。

因为是分布式的环境,放入queue中的数据需要等待Workers机器运算处理后再进行读取,这样就需要对queue用QueueManager进行封装放到网络中,这是通过上面的2行代码来实现的。我们给return_task_queue的网络调用接口取了一个名早纯get_task_queue,而return_result_queue的名字是get_result_queue,方便区分对哪个queue进行操作。task.put(n)即是对task_queue进行写入数据,相当于分配任务。而result.get()即是等待workers机器处理后返回的结果。

值得注意 在windows系统中你必须要写IP地址,而其他操作系统比如linux操作系统则就不要了。

修改后的代码

在task_master.py中修改如下:

在task_worker.py中修改如下:

先运行task_master.py,然后再运行task_worker.py

(1)task_master.py运行结果如下

(2)task_worker.py运行结果如下

知识补充

这个简单的Master/Worker模型有什么用?其实这就是一个简单但真正的分布式计算,把代码稍加改造,启动多个worker,就可以把任务分布到几台甚至几十台机器上,比如把计算n*n的代码换成发送邮件,就实现了邮件队列的异步发送。

Queue对象存储在哪?注意到task_worker.py中根本没有创建Queue的代码,所以,Queue对象存储在task_master.py进程中:

而Queue之所以能通过网络访问,就是通过QueueManager实现的。由于QueueManager管理的不止一个Queue,所以,要给每个Queue的网络调用接口起个名字,比如get_task_queue。task_worker这里的QueueManager注册的名字必须和task_manager中的一样。对比上面的例子,可以看出Queue对象从另一个进程通过网络传递了过来。只不过这里的传递和网络通信由QueueManager完成。

authkey有什么用?这是为了保证两台机器正常通信,不被其他机器恶意干扰。如果task_worker.py的authkey和task_master.py的authkey不一致,肯定连接不上。

4. 如何用 Python 从海量文本抽取主题

代码
我们在Jupyter Notebook中新建一个Python 2笔记本,起名为topic-model。

为了处理表格数据,我们依然使用数据框工具Pandas。先调用它。
import pandas as pd
然后读入我们的数据文件datascience.csv,注意它的编码是中文GB18030,不是Pandas默认设置的编码,所以此处需要显式指定编码类型,以免出现乱码错误。
df = pd.read_csv("datascience.csv", encoding='gb18030')
我们来看看数据框的头几行,以确认读取是否正确。
df.head()
显示结果如下:

没问题,头几行内容所有列都正确读入,文字显式正常。我们看看数据框的长度,以确认数据是否读取完整。
df.shape
执行的结果为:
(1024, 3)
行列数都与我们爬取到的数量一致,通过。
下面我们需要做一件重要工作——分词。这是因为我们需要提取每篇文章的关键词。而中文本身并不使用空格在单词间划分。

我们首先调用jieba分词包。
import jieba
我们此次需要处理的,不是单一文本数据,而是1000多条文本数据,因此我们需要把这项工作并行化。这就需要首先编写一个函数,处理单一文本的分词。
def chinese_word_cut(mytext):
return " ".join(jieba.cut(mytext))
有了这个函数之后,我们就可以不断调用它来批量处理数据框里面的全部文本(正文)信息了。你当然可以自己写个循环来做这项工作。
下面这一段代码执行起来,可能需要一小段时间。请耐心等候。
df["content_cutted"] = df.content.apply(chinese_word_cut)
执行过程中可能会出现如下提示。没关系,忽略就好。
Building prefix dict from the default dictionary ...
Loading model from cache /var/folders/8s//T/jieba.cache
Loading model cost 0.406 seconds.
Prefix dict has been built succesfully.
执行完毕之后,我们需要查看一下,文本是否已经被正确分词。
df.content_cutted.head()

热点内容
群晖怎么玩安卓模拟器 发布:2025-02-02 09:45:23 浏览:550
三星安卓12彩蛋怎么玩 发布:2025-02-02 09:44:39 浏览:736
电脑显示连接服务器错误 发布:2025-02-02 09:24:10 浏览:529
瑞芯微开发板编译 发布:2025-02-02 09:22:54 浏览:139
linux虚拟机用gcc编译时显示错误 发布:2025-02-02 09:14:01 浏览:227
java驼峰 发布:2025-02-02 09:13:26 浏览:644
魔兽脚本怎么用 发布:2025-02-02 09:10:28 浏览:527
linuxadobe 发布:2025-02-02 09:09:43 浏览:205
sql2000数据库连接 发布:2025-02-02 09:09:43 浏览:720
加密狗硬件克隆 发布:2025-02-02 08:59:16 浏览:462