【4858.com】牛逼的分分钟就将一个网址爬下来,写爬虫以及质量相比

By admin in 4858.com on 2019年4月10日

  用c语言写了kmeans算法的串行程序,再用mpi来写并行版的,貌似参照着串行版来写并行版,效果不是很清爽~

  用c语言写了kmeans算法的串行程序,再用mpi来写并行版的,貌似参照着串行版来写并行版,效果不是很喜笑颜开~

python选拔 多进度/多线程/协程 写爬虫以及质量比较,牛逼的分分钟就将一个网址爬下来!,python爬虫

 

首先大家来打听下python中的进度,线程以及协程!

从计算机硬件角度:

计算机的基本是CPU,承担了有着的测算任务。
三个CPU,在三个时间切片里只好运维1个顺序。

 

从操作系统的角度:

进程和线程,都以壹种CPU的进行单元。

经过:表示3个程序的上下文执行活动(打开、执行、保存…)

线程:进度执行顺序时候的小小调度单位(执行a,执行b…)

叁个主次至少有多个历程,一个历程至少有3个线程。

 

并行 和 并发:

相互:八个CPU宗旨,分化的次第就分配给不一致的CPU来运作。能够让三个程序同时执行。

cpu1 ————-
cpu2 ————-
cpu3 ————-
cpu4 ————-

出现:单个CPU大旨,在3个年华切片里二遍只可以运维叁个顺序,假使供给周转多少个程序,则串行执行。

cpu1  —-  —-

cpu1    —-  —-

 

多进程/多线程:
意味着能够而且进行八个任务,进程和线程的调度是由操作系统自动实现。

进程:每一个进度都有友好独立的内部存款和储蓄器空间,不一致进度之间的内部存款和储蓄器空间不共享。
进度之间的通讯有操作系统传递,导致通信作用低,切换开支大。

线程:二个经过能够有七个线程,所无线程共享进度的内存空间,通信功能高,切换开销小。

共享意味着竞争,导致数据不安全,为了维护内部存款和储蓄器空间的数量安全,引进”互斥锁”。

三个线程在造访内部存款和储蓄器空间的时候,其余线程不容许访问,必须等待此前的线程访问甘休,才能选拔这几个内部存款和储蓄器空间。

互斥锁:一种安全有序的让多少个线程访问内部存款和储蓄器空间的建制。

【4858.com】牛逼的分分钟就将一个网址爬下来,写爬虫以及质量相比。 

Python的八线程:

GIL 全局解释器锁:线程的推行权限,在Python的历程里唯有八个GIL。

2个线程供给履行任务,必须获得GIL。

利益:直接杜绝了多少个线程访问内部存款和储蓄器空间的新余难题。
弊病:Python的三十二线程不是真的八线程,不能够充足利用多核CPU的能源。

而是,在I/O阻塞的时候,解释器会释放GIL。

所以:

多进度:密集CPU职分,须求丰富行使多核CPU能源(服务器,大批量的并行计算)的时候,用多进度。
multiprocessing
缺陷:多个进度之间通讯开销高,切换费用大。

十二线程:密集I/O职务(互联网I/O,磁盘I/O,数据库I/O)使用八线程合适。
threading.Thread、multiprocessing.dummy
症结:同贰个小时切片只可以运转一个线程,不能够完毕高并行,可是足以做到高并发。

协程:又称微线程,在单线程上实施多少个任务,用函数切换,成本非常小。不通过操作系统调度,未有经过、线程的切换开支。genvent,monkey.patchall

二10二十四线程请求重临是冬辰的,那四个线程有数据重返就处理非凡线程,而协程再次回到的数据是平稳的。

缺陷:单线程执行,处理密集CPU和地点磁盘IO的时候,质量较低。处理互联网I/O品质依然比较高.

 

上面以这些网址为例,选用三种方式爬取。爬取前250名的电影。。

 通过分析网页发现第三页的url start=25,第一页的url
start=50,第3页的start=7伍。因而得以汲取这么些网址每1页的数局是透过递增start那一个参数获取的。

貌似不看率先页的多寡,第三页的尚未参考价值。

4858.com 1

 

此次大家重点爬取,电影名字跟评分。只是利用差别措施去对待下差异点,所以数据方面就只是多领取也许封存。只是简短的将其爬取下打字与印刷出来看看。

率先:选择多进度 , multiprocessing 模块。
当然那么些耗费时间更互联网好坏有关。在全部要请求都平常的气象下耗费时间一5s多。

 

4858.com 2

#!/usr/bin/env python2
# -*- coding=utf-8 -*-

from multiprocessing import Process, Queue

import time
from lxml import etree
import requests


class DouBanSpider(Process):
    def __init__(self, url, q):
        # 重写写父类的__init__方法
        super(DouBanSpider, self).__init__()
        self.url = url
        self.q = q
        self.headers = {
            'Host': 'movie.douban.com',
            'Referer': 'https://movie.douban.com/top250?start=225&filter=',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36',
        }

    def run(self):
        self.parse_page()

    def send_request(self,url):
        '''
        用来发送请求的方法
        :return: 返回网页源码
        '''
        # 请求出错时,重复请求3次,
        i = 0
        while i <= 3:
            try:
                print u"[INFO]请求url:"+url
                return requests.get(url=url,headers=self.headers).content
            except Exception as e:
                print u'[INFO] %s%s'% (e,url)
                i += 1

    def parse_page(self):
        '''
        解析网站源码,并采用xpath提取 电影名称和平分放到队列中
        :return:
        '''
        response = self.send_request(self.url)
        html = etree.HTML(response)
        # 获取到一页的电影数据
        node_list = html.xpath("//div[@class='info']")
        for move in node_list:
            # 电影名称
            title = move.xpath('.//a/span/text()')[0]
            # 评分
            score = move.xpath('.//div[@class="bd"]//span[@class="rating_num"]/text()')[0]

            # 将每一部电影的名称跟评分加入到队列
            self.q.put(score + "\t" + title)


def main():
    # 创建一个队列用来保存进程获取到的数据
    q = Queue()
    base_url = 'https://movie.douban.com/top250?start='
    # 构造所有url
    url_list = [base_url+str(num) for num in range(0,225+1,25)]

    # 保存进程
    Process_list = []
    # 创建并启动进程
    for url in url_list:
        p = DouBanSpider(url,q)
        p.start()
        Process_list.append(p)

    # 让主进程等待子进程执行完成
    for i in Process_list:
        i.join()

    while not q.empty():
        print q.get()

if __name__=="__main__":

    start = time.time()
    main()
    print '[info]耗时:%s'%(time.time()-start)

Process多进度达成

#!/usr/bin/env python2
# -*- coding=utf-8 -*-

from multiprocessing import Process, Queue

import time
from lxml import etree
import requests


class DouBanSpider(Process):
    def __init__(self, url, q):
        # 重写写父类的__init__方法
        super(DouBanSpider, self).__init__()
        self.url = url
        self.q = q
        self.headers = {
            'Host': 'movie.douban.com',
            'Referer': 'https://movie.douban.com/top250?start=225&filter=',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36',
        }

    def run(self):
        self.parse_page()

    def send_request(self,url):
        '''
        用来发送请求的方法
        :return: 返回网页源码
        '''
        # 请求出错时,重复请求3次,
        i = 0
        while i <= 3:
            try:
                print u"[INFO]请求url:"+url
                return requests.get(url=url,headers=self.headers).content
            except Exception as e:
                print u'[INFO] %s%s'% (e,url)
                i += 1

    def parse_page(self):
        '''
        解析网站源码,并采用xpath提取 电影名称和平分放到队列中
        :return:
        '''
        response = self.send_request(self.url)
        html = etree.HTML(response)
        # 获取到一页的电影数据
        node_list = html.xpath("//div[@class='info']")
        for move in node_list:
            # 电影名称
            title = move.xpath('.//a/span/text()')[0]
            # 评分
            score = move.xpath('.//div[@class="bd"]//span[@class="rating_num"]/text()')[0]

            # 将每一部电影的名称跟评分加入到队列
            self.q.put(score + "\t" + title)


def main():
    # 创建一个队列用来保存进程获取到的数据
    q = Queue()
    base_url = 'https://movie.douban.com/top250?start='
    # 构造所有url
    url_list = [base_url+str(num) for num in range(0,225+1,25)]

    # 保存进程
    Process_list = []
    # 创建并启动进程
    for url in url_list:
        p = DouBanSpider(url,q)
        p.start()
        Process_list.append(p)

    # 让主进程等待子进程执行完成
    for i in Process_list:
        i.join()

    while not q.empty():
        print q.get()

if __name__=="__main__":

    start = time.time()
    main()
    print '[info]耗时:%s'%(time.time()-start)

  

4858.com 3

 

 

 

  选取十二线程时,耗费时间10.4s

 

4858.com 4

#!/usr/bin/env python2
# -*- coding=utf-8 -*-

from threading import Thread
from Queue import Queue
import time
from lxml import etree
import requests


class DouBanSpider(Thread):
    def __init__(self, url, q):
        # 重写写父类的__init__方法
        super(DouBanSpider, self).__init__()
        self.url = url
        self.q = q
        self.headers = {
            'Cookie': 'll="118282"; bid=ctyiEarSLfw; ps=y; __yadk_uid=0Sr85yZ9d4bEeLKhv4w3695OFOPoedzC; dbcl2="155150959:OEu4dds1G1o"; as="https://sec.douban.com/b?r=https%3A%2F%2Fbook.douban.com%2F"; ck=fTrQ; _pk_id.100001.4cf6=c86baf05e448fb8d.1506160776.3.1507290432.1507283501.; _pk_ses.100001.4cf6=*; __utma=30149280.1633528206.1506160772.1507283346.1507290433.3; __utmb=30149280.0.10.1507290433; __utmc=30149280; __utmz=30149280.1506160772.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utma=223695111.1475767059.1506160772.1507283346.1507290433.3; __utmb=223695111.0.10.1507290433; __utmc=223695111; __utmz=223695111.1506160772.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); push_noty_num=0; push_doumail_num=0',
            'Host': 'movie.douban.com',
            'Referer': 'https://movie.douban.com/top250?start=225&filter=',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36',
        }

    def run(self):
        self.parse_page()

    def send_request(self,url):
        '''
        用来发送请求的方法
        :return: 返回网页源码
        '''
        # 请求出错时,重复请求3次,
        i = 0
        while i <= 3:
            try:
                print u"[INFO]请求url:"+url
                html = requests.get(url=url,headers=self.headers).content
            except Exception as e:
                print u'[INFO] %s%s'% (e,url)
                i += 1
            else:
                return html

    def parse_page(self):
        '''
        解析网站源码,并采用xpath提取 电影名称和平分放到队列中
        :return:
        '''
        response = self.send_request(self.url)
        html = etree.HTML(response)
        # 获取到一页的电影数据
        node_list = html.xpath("//div[@class='info']")
        for move in node_list:
            # 电影名称
            title = move.xpath('.//a/span/text()')[0]
            # 评分
            score = move.xpath('.//div[@class="bd"]//span[@class="rating_num"]/text()')[0]

            # 将每一部电影的名称跟评分加入到队列
            self.q.put(score + "\t" + title)


def main():
    # 创建一个队列用来保存进程获取到的数据
    q = Queue()
    base_url = 'https://movie.douban.com/top250?start='
    # 构造所有url
    url_list = [base_url+str(num) for num in range(0,225+1,25)]

    # 保存线程
    Thread_list = []
    # 创建并启动线程
    for url in url_list:
        p = DouBanSpider(url,q)
        p.start()
        Thread_list.append(p)

    # 让主线程等待子线程执行完成
    for i in Thread_list:
        i.join()

    while not q.empty():
        print q.get()

if __name__=="__main__":

    start = time.time()
    main()
    print '[info]耗时:%s'%(time.time()-start)

thread

#!/usr/bin/env python2
# -*- coding=utf-8 -*-

from threading import Thread
from Queue import Queue
import time
from lxml import etree
import requests


class DouBanSpider(Thread):
    def __init__(self, url, q):
        # 重写写父类的__init__方法
        super(DouBanSpider, self).__init__()
        self.url = url
        self.q = q
        self.headers = {
            'Cookie': 'll="118282"; bid=ctyiEarSLfw; ps=y; __yadk_uid=0Sr85yZ9d4bEeLKhv4w3695OFOPoedzC; dbcl2="155150959:OEu4dds1G1o"; as="https://sec.douban.com/b?r=https%3A%2F%2Fbook.douban.com%2F"; ck=fTrQ; _pk_id.100001.4cf6=c86baf05e448fb8d.1506160776.3.1507290432.1507283501.; _pk_ses.100001.4cf6=*; __utma=30149280.1633528206.1506160772.1507283346.1507290433.3; __utmb=30149280.0.10.1507290433; __utmc=30149280; __utmz=30149280.1506160772.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utma=223695111.1475767059.1506160772.1507283346.1507290433.3; __utmb=223695111.0.10.1507290433; __utmc=223695111; __utmz=223695111.1506160772.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); push_noty_num=0; push_doumail_num=0',
            'Host': 'movie.douban.com',
            'Referer': 'https://movie.douban.com/top250?start=225&filter=',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36',
        }

    def run(self):
        self.parse_page()

    def send_request(self,url):
        '''
        用来发送请求的方法
        :return: 返回网页源码
        '''
        # 请求出错时,重复请求3次,
        i = 0
        while i <= 3:
            try:
                print u"[INFO]请求url:"+url
                html = requests.get(url=url,headers=self.headers).content
            except Exception as e:
                print u'[INFO] %s%s'% (e,url)
                i += 1
            else:
                return html

    def parse_page(self):
        '''
        解析网站源码,并采用xpath提取 电影名称和平分放到队列中
        :return:
        '''
        response = self.send_request(self.url)
        html = etree.HTML(response)
        # 获取到一页的电影数据
        node_list = html.xpath("//div[@class='info']")
        for move in node_list:
            # 电影名称
            title = move.xpath('.//a/span/text()')[0]
            # 评分
            score = move.xpath('.//div[@class="bd"]//span[@class="rating_num"]/text()')[0]

            # 将每一部电影的名称跟评分加入到队列
            self.q.put(score + "\t" + title)


def main():
    # 创建一个队列用来保存进程获取到的数据
    q = Queue()
    base_url = 'https://movie.douban.com/top250?start='
    # 构造所有url
    url_list = [base_url+str(num) for num in range(0,225+1,25)]

    # 保存线程
    Thread_list = []
    # 创建并启动线程
    for url in url_list:
        p = DouBanSpider(url,q)
        p.start()
        Thread_list.append(p)

    # 让主线程等待子线程执行完成
    for i in Thread_list:
        i.join()

    while not q.empty():
        print q.get()

if __name__=="__main__":

    start = time.time()
    main()
    print '[info]耗时:%s'%(time.time()-start)

  

 4858.com 5

 

 

行使协程爬取,耗费时间15S,

4858.com 6

#!/usr/bin/env python2
# -*- coding=utf-8 -*-

from Queue import Queue
import time
from lxml import etree
import requests
import gevent

# 打上猴子补丁
from gevent import monkey
monkey.patch_all()

class DouBanSpider(object):
    def __init__(self):
        # 创建一个队列用来保存进程获取到的数据
        self.q = Queue()
        self.headers = {
            'Cookie': 'll="118282"; bid=ctyiEarSLfw; ps=y; __yadk_uid=0Sr85yZ9d4bEeLKhv4w3695OFOPoedzC; dbcl2="155150959:OEu4dds1G1o"; as="https://sec.douban.com/b?r=https%3A%2F%2Fbook.douban.com%2F"; ck=fTrQ; _pk_id.100001.4cf6=c86baf05e448fb8d.1506160776.3.1507290432.1507283501.; _pk_ses.100001.4cf6=*; __utma=30149280.1633528206.1506160772.1507283346.1507290433.3; __utmb=30149280.0.10.1507290433; __utmc=30149280; __utmz=30149280.1506160772.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utma=223695111.1475767059.1506160772.1507283346.1507290433.3; __utmb=223695111.0.10.1507290433; __utmc=223695111; __utmz=223695111.1506160772.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); push_noty_num=0; push_doumail_num=0',
            'Host': 'movie.douban.com',
            'Referer': 'https://movie.douban.com/top250?start=225&filter=',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36',
        }

    def run(self,url):
        self.parse_page(url)

    def send_request(self,url):
        '''
        用来发送请求的方法
        :return: 返回网页源码
        '''
        # 请求出错时,重复请求3次,
        i = 0
        while i <= 3:
            try:
                print u"[INFO]请求url:"+url
                html = requests.get(url=url,headers=self.headers).content
            except Exception as e:
                print u'[INFO] %s%s'% (e,url)
                i += 1
            else:
                return html

    def parse_page(self,url):
        '''
        解析网站源码,并采用xpath提取 电影名称和平分放到队列中
        :return:
        '''
        response = self.send_request(url)
        html = etree.HTML(response)
        # 获取到一页的电影数据
        node_list = html.xpath("//div[@class='info']")
        for move in node_list:
            # 电影名称
            title = move.xpath('.//a/span/text()')[0]
            # 评分
            score = move.xpath('.//div[@class="bd"]//span[@class="rating_num"]/text()')[0]

            # 将每一部电影的名称跟评分加入到队列
            self.q.put(score + "\t" + title)


    def main(self):


        base_url = 'https://movie.douban.com/top250?start='
        # 构造所有url
        url_list = [base_url+str(num) for num in range(0,225+1,25)]
        # 创建协程并执行
        job_list = [gevent.spawn(self.run,url) for url in url_list]
        # 让线程等待所有任务完成,再继续执行。
        gevent.joinall(job_list)

        while not self.q.empty():
            print self.q.get()

if __name__=="__main__":
    start = time.time()
    douban = DouBanSpider()
    douban.main()
    print '[info]耗时:%s'%(time.time()-start)

gevent

 

 4858.com 7

 

 

用了多进程,四线程,协程,完结的代码都同1,未有测试出明显的老大好!都不分上下,或许跟互联网,也许服务器配置有关。

但辩驳上的电话线程,协程在I/O密集的操作质量是要压倒进度的。

 

也大概是本人的点子有标题,还望大神们求教!

 

多进度/四线程/协程
写爬虫以及质量相比较,牛逼的分秒钟就将1个网站爬下来!,python爬虫
首先大家来询问下python中的进程,线程…

 

  

  

首先大家来打听下python中的进程,线程以及协程!

  并行化思路:

  并行化思路:

从计算机硬件角度:

  使用基本形式。由四个节点充当主节点负责数据的分开与分配,别的节点完毕地方数据的猜度,并将结果再次来到给主节点。大概进程如下:

  使用基本格局。由七个节点充当主节点负责数据的划分与分配,其余节点完开支地数据的估计,并将结果回到给主节点。大概进程如下:

微型总计机的基本是CPU,承担了有着的计算职责。
3个CPU,在三个时间切片里只好运维2个先后。

  1、进度0为主节点,先从文件中读取数据集,然后将数据集划分并传给别的进程;

  1、进度0为主节点,先从文件中读取数据集,然后将数据集划分并传给其余进度;

 

  二、进度0采取每一个聚类的核心点,并发送给别的进度;

  二、进度0采用各类聚类的基本点,并发送给其余进度;

从操作系统的角度:

  三、别的进度总结数据块中每种点到中央点的偏离,然后标出每一种点所属的聚类,并总结每种聚类全体点到里面心点的距离之和,最终将这几个结果重临给进程0;

  叁、别的进程总计数据块中种种点到焦点点的偏离,然后标出每一种点所属的聚类,并总计每种聚类全数点到内部心点的距离之和,最后将这个结果回到给进程0;

经过和线程,都是一种CPU的执行单元。

  四、进度0总计出新的大旨点并发送给别的进度,并盘算其余进度传来的聚类全体点到里头心点的离开总和;

  四、进度0计算出新的大旨点并发送给其余进度,并总结其余进程传来的聚类全数点到中间心点的偏离总和;

进度:表示3个先后的上下文执行活动(打开、执行、保存…)

  伍、重复三和4甘休,直到步骤肆中的全体聚类的偏离之和不变(即未有)。

  伍、重复3和四直到,直到步骤四中的全体聚类的相距之和不变(即未有)。

线程:进度执行顺序时候的微乎其微调度单位(执行a,执行b…)

 

 

叁个先后至少有多个历程,贰个历程至少有一个线程。

  code:

  code:

 

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <math.h>
  4 #include <time.h>
  5 #include "mpi.h"
  6 
  7 int  main(int argc,char *argv[])
  8 {
  9     int i,j;
 10     MPI_Status status;
 11     float temp1,temp2;
 12     int K,N,D;  //聚类的数目,数据量,数据的维数
 13     float **data;  //存放数据
 14     int *all_in_cluster;  //进程0标记每个点属于哪个聚类
 15     int *local_in_cluster;  //其他进程标记每个点属于哪个聚类
 16     int *in_cluster;  //进程0标记每个点属于哪个聚类
 17     int count=0;
 18     float *sum_diff;
 19     float *global_sum_diff;
 20     float **cluster_center;  //存放每个聚类的中心点
 21     int rank,size;
 22     float **array(int m,int n);
 23     float **loadData(int *k,int *d,int *n);
 24     float getDistance(float avector[],float bvector[],int n);
 25     void cluster(int n,int k,int d,float **data,float **cluster_center,int *local_in_cluster);
 26     float getDifference(int k,int n,int d,int *in_cluster,float **data,float **cluster_center,float *sum);
 27     void getCenter(int k,int d,int n,int *in_cluster,float **data,float **cluster_center);
 28 
 29     MPI_Init(&argc,&argv);
 30     MPI_Comm_rank(MPI_COMM_WORLD,&rank);
 31     MPI_Comm_size(MPI_COMM_WORLD,&size);
 32     if(!rank){
 33         data=loadData(&K,&D,&N);  //进程0读入数据
 34         if(size==1||size>N||N%(size-1))    MPI_Abort(MPI_COMM_WORLD,1);  //若不满足条件则退出
 35     }
 36     MPI_Bcast(&K,1,MPI_INT,0,MPI_COMM_WORLD);  //进程0广播
 37     MPI_Bcast(&N,1,MPI_INT,0,MPI_COMM_WORLD);  
 38     MPI_Bcast(&D,1,MPI_INT,0,MPI_COMM_WORLD);  
 39     if(rank)    data=array(N/(size-1),D);  //其他进程分配存储数据集的空间
 40     all_in_cluster=(int *)malloc(N/(size-1)*size*sizeof(int));  //用于进程0
 41     local_in_cluster=(int *)malloc(N/(size-1)*sizeof(int));  //用于每个进程
 42     in_cluster=(int *)malloc(N*sizeof(int));  //用于进程0
 43     sum_diff=(float *)malloc(K*sizeof(float));  //进程中每个聚类的数据点与其中心点的距离之和
 44     global_sum_diff=(float *)malloc(K*sizeof(float));
 45     for(i=0;i<K;i++)    sum_diff[i]=0.0;  //初始化
 46 
 47     if(!rank){  //进程0向其他进程分配数据集
 48         for(i=0;i<N;i+=(N/(size-1)))
 49             for(j=0;j<(N/(size-1));j++)
 50                 MPI_Send(data[i+j],D,MPI_FLOAT,(i+j)/(N/(size-1))+1,99,MPI_COMM_WORLD);  
 51         printf("Data sets:\n");
 52         for(i=0;i<N;i++)
 53             for(j=0;j<D;j++){
 54                 printf("%-8.2f",data[i][j]);
 55                 if((j+1)%D==0)    putchar('\n');
 56             }
 57            printf("-----------------------------\n");
 58     }else{  //其他进程接收进程0数据
 59         for(i=0;i<(N/(size-1));i++)
 60             MPI_Recv(data[i],D,MPI_FLOAT,0,99,MPI_COMM_WORLD,&status);
 61     }
 62     MPI_Barrier(MPI_COMM_WORLD);  //同步一下
 63     cluster_center=array(K,D);  //中心点 
 64     if(!rank){  //进程0产生随机中心点
 65         srand((unsigned int)(time(NULL)));  //随机初始化k个中心点
 66         for(i=0;i<K;i++)
 67             for(j=0;j<D;j++)
 68                 cluster_center[i][j]=data[(int)((double)N*rand()/(RAND_MAX+1.0))][j];
 69     }
 70     for(i=0;i<K;i++)    MPI_Bcast(cluster_center[i],D,MPI_FLOAT,0,MPI_COMM_WORLD);  //进程0向其他进程广播中心点
 71     if(rank){
 72         cluster(N/(size-1),K,D,data,cluster_center,local_in_cluster);  //其他进程进行聚类
 73         getDifference(K,N/(size-1),D,local_in_cluster,data,cluster_center,sum_diff);
 74         for(i=0;i<N/(size-1);i++)
 75             printf("data[%d] in cluster-%d\n",(rank-1)*(N/(size-1))+i,local_in_cluster[i]+1);
 76     }
 77     MPI_Gather(local_in_cluster,N/(size-1),MPI_INT,all_in_cluster,N/(size-1),MPI_INT,0,MPI_COMM_WORLD);  //全收集于进程0
 78     MPI_Reduce(sum_diff,global_sum_diff,K,MPI_FLOAT,MPI_SUM,0,MPI_COMM_WORLD);  //归约至进程0,进程中每个聚类的数据点与其中心点的距离之和
 79     if(!rank){  
 80         for(i=N/(size-1);i<N+N/(size-1);i++) 
 81             in_cluster[i-N/(size-1)]=all_in_cluster[i];  //处理收集的标记数组
 82         temp1=0.0;
 83         for(i=0;i<K;i++) temp1+=global_sum_diff[i];
 84         printf("The difference between data and center is: %.2f\n\n", temp1);
 85         count++;
 86     }
 87     MPI_Bcast(&temp1,1,MPI_FLOAT,0,MPI_COMM_WORLD);
 88     MPI_Barrier(MPI_COMM_WORLD);
 89 
 90     do{   //比较前后两次迭代,若不相等继续迭代
 91         temp1=temp2;
 92         if(!rank)    getCenter(K,D,N,in_cluster,data,cluster_center);  //更新中心点
 93         for(i=0;i<K;i++)    MPI_Bcast(cluster_center[i],D,MPI_FLOAT,0,MPI_COMM_WORLD);  //广播中心点    
 94         if(rank){
 95             cluster(N/(size-1),K,D,data,cluster_center,local_in_cluster);  //其他进程进行聚类
 96             for(i=0;i<K;i++)    sum_diff[i]=0.0;
 97             getDifference(K,N/(size-1),D,local_in_cluster,data,cluster_center,sum_diff);
 98             for(i=0;i<N/(size-1);i++)
 99                 printf("data[%d] in cluster-%d\n",(rank-1)*(N/(size-1))+i,local_in_cluster[i]+1);
100         }
101         MPI_Gather(local_in_cluster,N/(size-1),MPI_INT,all_in_cluster,N/(size-1),MPI_INT,0,MPI_COMM_WORLD);
102         if(!rank)
103             for(i=0;i<K;i++)    global_sum_diff[i]=0.0;
104         MPI_Reduce(sum_diff,global_sum_diff,K,MPI_FLOAT,MPI_SUM,0,MPI_COMM_WORLD);
105         if(!rank){
106             for(i=N/(size-1);i<N+N/(size-1);i++) 
107                 in_cluster[i-N/(size-1)]=all_in_cluster[i];
108             temp2=0.0;
109             for(i=0;i<K;i++) temp2+=global_sum_diff[i];
110             printf("The difference between data and center is: %.2f\n\n", temp2);
111             count++;
112         }
113         MPI_Bcast(&temp2,1,MPI_FLOAT,0,MPI_COMM_WORLD);
114         MPI_Barrier(MPI_COMM_WORLD);
115     }while(fabs(temp2-temp1)!=0.0);
116     if(!rank)    printf("The total number of cluster is: %d\n\n",count);
117     MPI_Finalize();
118 }
119 
120 
121 //动态创建二维数组
122 float **array(int m,int n)
123 {
124     int i;
125     float **p;
126     p=(float **)malloc(m*sizeof(float *));
127     p[0]=(float *)malloc(m*n*sizeof(float));
128     for(i=1;i<m;i++)    p[i]=p[i-1]+n;
129     return p;
130 }
131 
132 //从data.txt导入数据,要求首行格式:K=聚类数目,D=数据维度,N=数据量
133 float **loadData(int *k,int *d,int *n)
134 {
135     float **array(int m,int n);
136     int i,j;
137     float **arraydata;
138     FILE *fp;
139     if((fp=fopen("data.txt","r"))==NULL)    fprintf(stderr,"cannot open data.txt!\n");
140     if(fscanf(fp,"K=%d,D=%d,N=%d\n",k,d,n)!=3)    fprintf(stderr,"load error!\n");
141     arraydata=array(*n,*d);  //生成数据数组
142     for(i=0;i<*n;i++)
143         for(j=0;j<*d;j++)
144             fscanf(fp,"%f",&arraydata[i][j]);  //读取数据点
145     return arraydata;
146 }
147 
148 //计算欧几里得距离
149 float getDistance(float avector[],float bvector[],int n)
150 {
151     int i;
152     float sum=0.0;
153     for(i=0;i<n;i++)
154         sum+=pow(avector[i]-bvector[i],2);
155     return sqrt(sum);
156 }
157 
158 //把N个数据点聚类,标出每个点属于哪个聚类
159 void cluster(int n,int k,int d,float **data,float **cluster_center,int *local_in_cluster)
160 {
161     int i,j;
162     float min;
163     float **distance=array(n,k);  //存放每个数据点到每个中心点的距离
164     for(i=0;i<n;++i){
165         min=9999.0;
166         for(j=0;j<k;++j){
167             distance[i][j] = getDistance(data[i],cluster_center[j],d);
168             if(distance[i][j]<min){
169             min=distance[i][j];
170             local_in_cluster[i]=j;
171         }
172        }
173     }
174     printf("-----------------------------\n");
175     free(distance);
176 }
177 
178 //计算所有聚类的中心点与其数据点的距离之和
179 float getDifference(int k,int n,int d,int *in_cluster,float **data,float **cluster_center,float *sum)
180 {
181     int i,j;
182     for(i=0;i<k;++i)
183         for(j=0;j<n;++j)
184             if(i==in_cluster[j])
185                 sum[i]+=getDistance(data[j],cluster_center[i],d);
186 }
187 
188 //计算每个聚类的中心点
189 void getCenter(int k,int d,int n,int *in_cluster,float **data,float **cluster_center)
190 {
191     float **sum=array(k,d);  //存放每个聚类中心
192     int i,j,q,count;
193     for(i=0;i<k;i++)
194         for(j=0;j<d;j++)
195             sum[i][j]=0.0;
196     for(i=0;i<k;i++){
197         count=0;  //统计属于某个聚类内的所有数据点
198         for(j=0;j<n;j++){
199             if(i==in_cluster[j]){
200                 for(q=0;q<d;q++)
201                     sum[i][q]+=data[j][q];  //计算所属聚类的所有数据点的相应维数之和
202                 count++;
203             }
204         }
205         for(q=0;q<d;q++)
206             cluster_center[i][q]=sum[i][q]/count;
207     }
208     printf("The new center of cluster is:\n");
209         for(i = 0; i < k; i++)
210             for(q=0;q<d;q++){
211                 printf("%-8.2f",cluster_center[i][q]);
212                 if((q+1)%d==0)    putchar('\n');
213     }
214     free(sum);
215 }
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <math.h>
  4 #include <time.h>
  5 #include "mpi.h"
  6 
  7 int  main(int argc,char *argv[])
  8 {
  9     int i,j;
 10     MPI_Status status;
 11     float temp1,temp2;
 12     int K,N,D;  //聚类的数目,数据量,数据的维数
 13     float **data;  //存放数据
 14     int *all_in_cluster;  //进程0标记每个点属于哪个聚类
 15     int *local_in_cluster;  //其他进程标记每个点属于哪个聚类
 16     int *in_cluster;  //进程0标记每个点属于哪个聚类
 17     int count=0;
 18     float *sum_diff;
 19     float *global_sum_diff;
 20     float **cluster_center;  //存放每个聚类的中心点
 21     int rank,size;
 22     float **array(int m,int n);
 23     float **loadData(int *k,int *d,int *n);
 24     float getDistance(float avector[],float bvector[],int n);
 25     void cluster(int n,int k,int d,float **data,float **cluster_center,int *local_in_cluster);
 26     float getDifference(int k,int n,int d,int *in_cluster,float **data,float **cluster_center,float *sum);
 27     void getCenter(int k,int d,int n,int *in_cluster,float **data,float **cluster_center);
 28 
 29     MPI_Init(&argc,&argv);
 30     MPI_Comm_rank(MPI_COMM_WORLD,&rank);
 31     MPI_Comm_size(MPI_COMM_WORLD,&size);
 32     if(!rank){
 33         data=loadData(&K,&D,&N);  //进程0读入数据
 34         if(size==1||size>N||N%(size-1))    MPI_Abort(MPI_COMM_WORLD,1);  //若不满足条件则退出
 35     }
 36     MPI_Bcast(&K,1,MPI_INT,0,MPI_COMM_WORLD);  //进程0广播
 37     MPI_Bcast(&N,1,MPI_INT,0,MPI_COMM_WORLD);  
 38     MPI_Bcast(&D,1,MPI_INT,0,MPI_COMM_WORLD);  
 39     if(rank)    data=array(N/(size-1),D);  //其他进程分配存储数据集的空间
 40     all_in_cluster=(int *)malloc(N/(size-1)*size*sizeof(int));  //用于进程0
 41     local_in_cluster=(int *)malloc(N/(size-1)*sizeof(int));  //用于每个进程
 42     in_cluster=(int *)malloc(N*sizeof(int));  //用于进程0
 43     sum_diff=(float *)malloc(K*sizeof(float));  //进程中每个聚类的数据点与其中心点的距离之和
 44     global_sum_diff=(float *)malloc(K*sizeof(float));
 45     for(i=0;i<K;i++)    sum_diff[i]=0.0;  //初始化
 46 
 47     if(!rank){  //进程0向其他进程分配数据集
 48         for(i=0;i<N;i+=(N/(size-1)))
 49             for(j=0;j<(N/(size-1));j++)
 50                 MPI_Send(data[i+j],D,MPI_FLOAT,(i+j)/(N/(size-1))+1,99,MPI_COMM_WORLD);  
 51         printf("Data sets:\n");
 52         for(i=0;i<N;i++)
 53             for(j=0;j<D;j++){
 54                 printf("%-8.2f",data[i][j]);
 55                 if((j+1)%D==0)    putchar('\n');
 56             }
 57            printf("-----------------------------\n");
 58     }else{  //其他进程接收进程0数据
 59         for(i=0;i<(N/(size-1));i++)
 60             MPI_Recv(data[i],D,MPI_FLOAT,0,99,MPI_COMM_WORLD,&status);
 61     }
 62     MPI_Barrier(MPI_COMM_WORLD);  //同步一下
 63     cluster_center=array(K,D);  //中心点 
 64     if(!rank){  //进程0产生随机中心点
 65         srand((unsigned int)(time(NULL)));  //随机初始化k个中心点
 66         for(i=0;i<K;i++)
 67             for(j=0;j<D;j++)
 68                 cluster_center[i][j]=data[(int)((double)N*rand()/(RAND_MAX+1.0))][j];
 69     }
 70     for(i=0;i<K;i++)    MPI_Bcast(cluster_center[i],D,MPI_FLOAT,0,MPI_COMM_WORLD);  //进程0向其他进程广播中心点
 71     if(rank){
 72         cluster(N/(size-1),K,D,data,cluster_center,local_in_cluster);  //其他进程进行聚类
 73         getDifference(K,N/(size-1),D,local_in_cluster,data,cluster_center,sum_diff);
 74         for(i=0;i<N/(size-1);i++)
 75             printf("data[%d] in cluster-%d\n",(rank-1)*(N/(size-1))+i,local_in_cluster[i]+1);
 76     }
 77     MPI_Gather(local_in_cluster,N/(size-1),MPI_INT,all_in_cluster,N/(size-1),MPI_INT,0,MPI_COMM_WORLD);  //全收集于进程0
 78     MPI_Reduce(sum_diff,global_sum_diff,K,MPI_FLOAT,MPI_SUM,0,MPI_COMM_WORLD);  //归约至进程0,进程中每个聚类的数据点与其中心点的距离之和
 79     if(!rank){  
 80         for(i=N/(size-1);i<N+N/(size-1);i++) 
 81             in_cluster[i-N/(size-1)]=all_in_cluster[i];  //处理收集的标记数组
 82         temp1=0.0;
 83         for(i=0;i<K;i++) temp1+=global_sum_diff[i];
 84         printf("The difference between data and center is: %.2f\n\n", temp1);
 85         count++;
 86     }
 87     MPI_Bcast(&temp1,1,MPI_FLOAT,0,MPI_COMM_WORLD);
 88     MPI_Barrier(MPI_COMM_WORLD);
 89 
 90     do{   //比较前后两次迭代,若不相等继续迭代
 91         temp1=temp2;
 92         if(!rank)    getCenter(K,D,N,in_cluster,data,cluster_center);  //更新中心点
 93         for(i=0;i<K;i++)    MPI_Bcast(cluster_center[i],D,MPI_FLOAT,0,MPI_COMM_WORLD);  //广播中心点    
 94         if(rank){
 95             cluster(N/(size-1),K,D,data,cluster_center,local_in_cluster);  //其他进程进行聚类
 96             for(i=0;i<K;i++)    sum_diff[i]=0.0;
 97             getDifference(K,N/(size-1),D,local_in_cluster,data,cluster_center,sum_diff);
 98             for(i=0;i<N/(size-1);i++)
 99                 printf("data[%d] in cluster-%d\n",(rank-1)*(N/(size-1))+i,local_in_cluster[i]+1);
100         }
101         MPI_Gather(local_in_cluster,N/(size-1),MPI_INT,all_in_cluster,N/(size-1),MPI_INT,0,MPI_COMM_WORLD);
102         if(!rank)
103             for(i=0;i<K;i++)    global_sum_diff[i]=0.0;
104         MPI_Reduce(sum_diff,global_sum_diff,K,MPI_FLOAT,MPI_SUM,0,MPI_COMM_WORLD);
105         if(!rank){
106             for(i=N/(size-1);i<N+N/(size-1);i++) 
107                 in_cluster[i-N/(size-1)]=all_in_cluster[i];
108             temp2=0.0;
109             for(i=0;i<K;i++) temp2+=global_sum_diff[i];
110             printf("The difference between data and center is: %.2f\n\n", temp2);
111             count++;
112         }
113         MPI_Bcast(&temp2,1,MPI_FLOAT,0,MPI_COMM_WORLD);
114         MPI_Barrier(MPI_COMM_WORLD);
115     }while(fabs(temp2-temp1)!=0.0);
116     if(!rank)    printf("The total number of cluster is: %d\n\n",count);
117     MPI_Finalize();
118 }
119 
120 
121 //动态创建二维数组
122 float **array(int m,int n)
123 {
124     int i;
125     float **p;
126     p=(float **)malloc(m*sizeof(float *));
127     p[0]=(float *)malloc(m*n*sizeof(float));
128     for(i=1;i<m;i++)    p[i]=p[i-1]+n;
129     return p;
130 }
131 
132 //从data.txt导入数据,要求首行格式:K=聚类数目,D=数据维度,N=数据量
133 float **loadData(int *k,int *d,int *n)
134 {
135     float **array(int m,int n);
136     int i,j;
137     float **arraydata;
138     FILE *fp;
139     if((fp=fopen("data.txt","r"))==NULL)    fprintf(stderr,"cannot open data.txt!\n");
140     if(fscanf(fp,"K=%d,D=%d,N=%d\n",k,d,n)!=3)    fprintf(stderr,"load error!\n");
141     arraydata=array(*n,*d);  //生成数据数组
142     for(i=0;i<*n;i++)
143         for(j=0;j<*d;j++)
144             fscanf(fp,"%f",&arraydata[i][j]);  //读取数据点
145     return arraydata;
146 }
147 
148 //计算欧几里得距离
149 float getDistance(float avector[],float bvector[],int n)
150 {
151     int i;
152     float sum=0.0;
153     for(i=0;i<n;i++)
154         sum+=pow(avector[i]-bvector[i],2);
155     return sqrt(sum);
156 }
157 
158 //把N个数据点聚类,标出每个点属于哪个聚类
159 void cluster(int n,int k,int d,float **data,float **cluster_center,int *local_in_cluster)
160 {
161     int i,j;
162     float min;
163     float **distance=array(n,k);  //存放每个数据点到每个中心点的距离
164     for(i=0;i<n;++i){
165         min=9999.0;
166         for(j=0;j<k;++j){
167             distance[i][j] = getDistance(data[i],cluster_center[j],d);
168             if(distance[i][j]<min){
169             min=distance[i][j];
170             local_in_cluster[i]=j;
171         }
172        }
173     }
174     printf("-----------------------------\n");
175     free(distance);
176 }
177 
178 //计算所有聚类的中心点与其数据点的距离之和
179 float getDifference(int k,int n,int d,int *in_cluster,float **data,float **cluster_center,float *sum)
180 {
181     int i,j;
182     for(i=0;i<k;++i)
183         for(j=0;j<n;++j)
184             if(i==in_cluster[j])
185                 sum[i]+=getDistance(data[j],cluster_center[i],d);
186 }
187 
188 //计算每个聚类的中心点
189 void getCenter(int k,int d,int n,int *in_cluster,float **data,float **cluster_center)
190 {
191     float **sum=array(k,d);  //存放每个聚类中心
192     int i,j,q,count;
193     for(i=0;i<k;i++)
194         for(j=0;j<d;j++)
195             sum[i][j]=0.0;
196     for(i=0;i<k;i++){
197         count=0;  //统计属于某个聚类内的所有数据点
198         for(j=0;j<n;j++){
199             if(i==in_cluster[j]){
200                 for(q=0;q<d;q++)
201                     sum[i][q]+=data[j][q];  //计算所属聚类的所有数据点的相应维数之和
202                 count++;
203             }
204         }
205         for(q=0;q<d;q++)
206             cluster_center[i][q]=sum[i][q]/count;
207     }
208     printf("The new center of cluster is:\n");
209         for(i = 0; i < k; i++)
210             for(q=0;q<d;q++){
211                 printf("%-8.2f",cluster_center[i][q]);
212                 if((q+1)%d==0)    putchar('\n');
213     }
214     free(sum);
215 }

并行 和 并发:

  

  

相互:五个CPU主旨,分化的次第就分配给不一样的CPU来运维。能够让多少个程序同时履行。

 1 //生成测试数据
 2 #include<stdio.h>
 3 #include<stdlib.h>
 4 #include<time.h>
 5 #define N 1000
 6 
 7 int main()
 8 {
 9     int i;
10     float a;
11     int k,d,n;
12     FILE *fp;
13     fprintf(stdout,"input(k d n):");
14     scanf("%d%d%d",&k,&d,&n);
15     if((fp=fopen("data.txt","w"))==NULL)    exit(1);
16     fprintf(fp,"K=%d,D=%d,N=%d\n",k,d,n);
17     srand((unsigned int)(time(NULL)));
18     for(i=1;i<=d*n;i++){
19         a=(int)(1.0+(double)N*rand()/(RAND_MAX+1.0));
20         fprintf(fp,"%.2f ",a);
21         if(i%d==0) putc('\n',fp);
22     }
23     if(fclose(fp)) exit(2);
24 }
 1 //生成测试数据
 2 #include<stdio.h>
 3 #include<stdlib.h>
 4 #include<time.h>
 5 #define N 1000
 6 
 7 int main()
 8 {
 9     int i;
10     float a;
11     int k,d,n;
12     FILE *fp;
13     fprintf(stdout,"input(k d n):");
14     scanf("%d%d%d",&k,&d,&n);
15     if((fp=fopen("data.txt","w"))==NULL)    exit(1);
16     fprintf(fp,"K=%d,D=%d,N=%d\n",k,d,n);
17     srand((unsigned int)(time(NULL)));
18     for(i=1;i<=d*n;i++){
19         a=(int)(1.0+(double)N*rand()/(RAND_MAX+1.0));
20         fprintf(fp,"%.2f ",a);
21         if(i%d==0) putc('\n',fp);
22     }
23     if(fclose(fp)) exit(2);
24 }

cpu1 ————-
cpu2 ————-
cpu3 ————-
cpu4 ————-

 

 

并发:单个CPU主旨,在三个日子切片里二遍只好运维三个顺序,假如急需周转几个程序,则串行执行。

  实验:

  实验:

cpu1  —-  —-

  聚类数K=十,数据的维度D=二,单位(秒):

  聚类数K=10,数据的维度D=2,单位(秒):

cpu1    —-  —-

数据量N

10000

100000

500000

串行

1

21

109

并行(2个进程)

2

25

101

并行(3个进程)

3

26

101

数据量N

10000

100000

500000

串行

1

21

109

并行(2个进程)

2

25

101

并行(3个进程)

3

26

101

 

  

  

多进程/多线程:
意味着能够同时实施多少个职责,进度和线程的调度是由操作系统自动完结。

 

 

进度:每个进度都有友好单身的内部存款和储蓄器空间,差别进程之间的内存空间不共享。
进度之间的通讯有操作系统传递,导致通信成效低,切换费用大。

 

 

线程:四个历程能够有两个线程,全数线程共享进度的内部存款和储蓄器空间,通信功能高,切换花费小。

 

 

共享意味着竞争,导致数据不安全,为了珍爱内部存款和储蓄器空间的数目安全,引进”互斥锁”。

 

 

一个线程在造访内部存款和储蓄器空间的时候,别的线程不允许访问,必须等待之前的线程访问停止,才能选用那一个内部存款和储蓄器空间。

 

 

互斥锁:一种安全有序的让多个线程访问内部存款和储蓄器空间的编写制定。

  分析:电脑配置是奔腾双核,根据该并行程序,三个中坚用作主节点以分配数据集,另三个骨干作为负责了绝超过十二分之5测算任务的节点。当数据量较小时,并行程序花在进度间数据通信的年月占了完全时间的相当的大比重,所以并行程序耗费时间要多于串行程序。在本电脑CPU为四个基本的条件下,当数据量较大时,并行程序与串行程序耗费时间非凡或然稍微偏小。在CPU大旨数在三个以上时,该并行程序的优势才显流露来。

  分析:电脑配置是奔腾双核,依据该并行程序,2个主旨用作主节点以分配数据集,另一个中坚作为负责了绝大多数测算职分的节点。当数据量较时辰,并行程序花在进程间数据通讯的日子占了完全时间的十分大比例,所以并行程序耗费时间要多于串行程序。在本电脑CPU为多少个基本的条件下,当数据量较大时,并行程序与串行程序耗费时间十二分或许稍微偏小。在CPU主题数在二个以上时,该并行程序的优势才显流露来。

 

 

 

Python的拾贰线程:

GIL 全局解释器锁:线程的推行权限,在Python的历程里唯有3个GIL。

2个线程须要履行任务,必须取得GIL。

好处:直接杜绝了三个线程访问内部存款和储蓄器空间的平安难点。
弊病:Python的102线程不是真正拾二线程,不能够丰盛利用多核CPU的财富。

可是,在I/O阻塞的时候,解释器会自由GIL。

所以:

多进程:密集CPU任务,须求丰盛使用多核CPU财富(服务器,大批量的并行总括)的时候,用多进程。
multiprocessing
症结:四个经过之间通讯费用高,切换开支大。

多线程:密集I/O职务(网络I/O,磁盘I/O,数据库I/O)使用多线程合适。
threading.Thread、multiprocessing.dummy
缺点:同二个时刻切片只可以运维二个线程,不可能成功高并行,可是足以做到高并发。

协程:又称微线程,在单线程上实施多少个任务,用函数切换,成本相当小。不通过操作系统调度,没有经过、线程的切换开支。genvent,monkey.patchall

多线程请求再次来到是冬日的,那多少个线程有数量重回就处理相当线程,而协程再次来到的数据是平稳的。

缺陷:单线程执行,处理密集CPU和当地球磁性盘IO的时候,品质较低。处理互连网I/O品质依然比较高.

 

上面以这一个网址为例,选拔三种情势爬取。爬取前250名的摄像。。

 通过分析网页发现第二页的url start=25,第一页的url
start=50,第3页的start=75。因而得以汲取那几个网址每一页的数局是经过递增start那一个参数获取的。

貌似不看率先页的多少,第2页的从未有过参考价值。

4858.com 8

 

此番大家第二爬取,电影名字跟评分。只是利用不相同方式去对待下差异点,所以数据方面就只是多领取恐怕封存。只是不难的将其爬取下打字与印刷出来看看。

率先:选择多进度 , multiprocessing 模块。
当然这几个耗时更网络好坏有关。在总体要乞请都健康的气象下耗费时间一五s多。

 

4858.com 94858.com 10

#!/usr/bin/env python2
# -*- coding=utf-8 -*-

from multiprocessing import Process, Queue

import time
from lxml import etree
import requests


class DouBanSpider(Process):
    def __init__(self, url, q):
        # 重写写父类的__init__方法
        super(DouBanSpider, self).__init__()
        self.url = url
        self.q = q
        self.headers = {
            'Host': 'movie.douban.com',
            'Referer': 'https://movie.douban.com/top250?start=225&filter=',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36',
        }

    def run(self):
        self.parse_page()

    def send_request(self,url):
        '''
        用来发送请求的方法
        :return: 返回网页源码
        '''
        # 请求出错时,重复请求3次,
        i = 0
        while i <= 3:
            try:
                print u"[INFO]请求url:"+url
                return requests.get(url=url,headers=self.headers).content
            except Exception as e:
                print u'[INFO] %s%s'% (e,url)
                i += 1

    def parse_page(self):
        '''
        解析网站源码,并采用xpath提取 电影名称和平分放到队列中
        :return:
        '''
        response = self.send_request(self.url)
        html = etree.HTML(response)
        # 获取到一页的电影数据
        node_list = html.xpath("//div[@class='info']")
        for move in node_list:
            # 电影名称
            title = move.xpath('.//a/span/text()')[0]
            # 评分
            score = move.xpath('.//div[@class="bd"]//span[@class="rating_num"]/text()')[0]

            # 将每一部电影的名称跟评分加入到队列
            self.q.put(score + "\t" + title)


def main():
    # 创建一个队列用来保存进程获取到的数据
    q = Queue()
    base_url = 'https://movie.douban.com/top250?start='
    # 构造所有url
    url_list = [base_url+str(num) for num in range(0,225+1,25)]

    # 保存进程
    Process_list = []
    # 创建并启动进程
    for url in url_list:
        p = DouBanSpider(url,q)
        p.start()
        Process_list.append(p)

    # 让主进程等待子进程执行完成
    for i in Process_list:
        i.join()

    while not q.empty():
        print q.get()

if __name__=="__main__":

    start = time.time()
    main()
    print '[info]耗时:%s'%(time.time()-start)

Process多进度达成

#!/usr/bin/env python2
# -*- coding=utf-8 -*-

from multiprocessing import Process, Queue

import time
from lxml import etree
import requests


class DouBanSpider(Process):
    def __init__(self, url, q):
        # 重写写父类的__init__方法
        super(DouBanSpider, self).__init__()
        self.url = url
        self.q = q
        self.headers = {
            'Host': 'movie.douban.com',
            'Referer': 'https://movie.douban.com/top250?start=225&filter=',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36',
        }

    def run(self):
        self.parse_page()

    def send_request(self,url):
        '''
        用来发送请求的方法
        :return: 返回网页源码
        '''
        # 请求出错时,重复请求3次,
        i = 0
        while i <= 3:
            try:
                print u"[INFO]请求url:"+url
                return requests.get(url=url,headers=self.headers).content
            except Exception as e:
                print u'[INFO] %s%s'% (e,url)
                i += 1

    def parse_page(self):
        '''
        解析网站源码,并采用xpath提取 电影名称和平分放到队列中
        :return:
        '''
        response = self.send_request(self.url)
        html = etree.HTML(response)
        # 获取到一页的电影数据
        node_list = html.xpath("//div[@class='info']")
        for move in node_list:
            # 电影名称
            title = move.xpath('.//a/span/text()')[0]
            # 评分
            score = move.xpath('.//div[@class="bd"]//span[@class="rating_num"]/text()')[0]

            # 将每一部电影的名称跟评分加入到队列
            self.q.put(score + "\t" + title)


def main():
    # 创建一个队列用来保存进程获取到的数据
    q = Queue()
    base_url = 'https://movie.douban.com/top250?start='
    # 构造所有url
    url_list = [base_url+str(num) for num in range(0,225+1,25)]

    # 保存进程
    Process_list = []
    # 创建并启动进程
    for url in url_list:
        p = DouBanSpider(url,q)
        p.start()
        Process_list.append(p)

    # 让主进程等待子进程执行完成
    for i in Process_list:
        i.join()

    while not q.empty():
        print q.get()

if __name__=="__main__":

    start = time.time()
    main()
    print '[info]耗时:%s'%(time.time()-start)

  

4858.com 11

4858.com , 

 

 

  采取四线程时,耗费时间十.四s

 

4858.com 124858.com 13

#!/usr/bin/env python2
# -*- coding=utf-8 -*-

from threading import Thread
from Queue import Queue
import time
from lxml import etree
import requests


class DouBanSpider(Thread):
    def __init__(self, url, q):
        # 重写写父类的__init__方法
        super(DouBanSpider, self).__init__()
        self.url = url
        self.q = q
        self.headers = {
            'Cookie': 'll="118282"; bid=ctyiEarSLfw; ps=y; __yadk_uid=0Sr85yZ9d4bEeLKhv4w3695OFOPoedzC; dbcl2="155150959:OEu4dds1G1o"; as="https://sec.douban.com/b?r=https%3A%2F%2Fbook.douban.com%2F"; ck=fTrQ; _pk_id.100001.4cf6=c86baf05e448fb8d.1506160776.3.1507290432.1507283501.; _pk_ses.100001.4cf6=*; __utma=30149280.1633528206.1506160772.1507283346.1507290433.3; __utmb=30149280.0.10.1507290433; __utmc=30149280; __utmz=30149280.1506160772.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utma=223695111.1475767059.1506160772.1507283346.1507290433.3; __utmb=223695111.0.10.1507290433; __utmc=223695111; __utmz=223695111.1506160772.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); push_noty_num=0; push_doumail_num=0',
            'Host': 'movie.douban.com',
            'Referer': 'https://movie.douban.com/top250?start=225&filter=',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36',
        }

    def run(self):
        self.parse_page()

    def send_request(self,url):
        '''
        用来发送请求的方法
        :return: 返回网页源码
        '''
        # 请求出错时,重复请求3次,
        i = 0
        while i <= 3:
            try:
                print u"[INFO]请求url:"+url
                html = requests.get(url=url,headers=self.headers).content
            except Exception as e:
                print u'[INFO] %s%s'% (e,url)
                i += 1
            else:
                return html

    def parse_page(self):
        '''
        解析网站源码,并采用xpath提取 电影名称和平分放到队列中
        :return:
        '''
        response = self.send_request(self.url)
        html = etree.HTML(response)
        # 获取到一页的电影数据
        node_list = html.xpath("//div[@class='info']")
        for move in node_list:
            # 电影名称
            title = move.xpath('.//a/span/text()')[0]
            # 评分
            score = move.xpath('.//div[@class="bd"]//span[@class="rating_num"]/text()')[0]

            # 将每一部电影的名称跟评分加入到队列
            self.q.put(score + "\t" + title)


def main():
    # 创建一个队列用来保存进程获取到的数据
    q = Queue()
    base_url = 'https://movie.douban.com/top250?start='
    # 构造所有url
    url_list = [base_url+str(num) for num in range(0,225+1,25)]

    # 保存线程
    Thread_list = []
    # 创建并启动线程
    for url in url_list:
        p = DouBanSpider(url,q)
        p.start()
        Thread_list.append(p)

    # 让主线程等待子线程执行完成
    for i in Thread_list:
        i.join()

    while not q.empty():
        print q.get()

if __name__=="__main__":

    start = time.time()
    main()
    print '[info]耗时:%s'%(time.time()-start)

thread

#!/usr/bin/env python2
# -*- coding=utf-8 -*-

from threading import Thread
from Queue import Queue
import time
from lxml import etree
import requests


class DouBanSpider(Thread):
    def __init__(self, url, q):
        # 重写写父类的__init__方法
        super(DouBanSpider, self).__init__()
        self.url = url
        self.q = q
        self.headers = {
            'Cookie': 'll="118282"; bid=ctyiEarSLfw; ps=y; __yadk_uid=0Sr85yZ9d4bEeLKhv4w3695OFOPoedzC; dbcl2="155150959:OEu4dds1G1o"; as="https://sec.douban.com/b?r=https%3A%2F%2Fbook.douban.com%2F"; ck=fTrQ; _pk_id.100001.4cf6=c86baf05e448fb8d.1506160776.3.1507290432.1507283501.; _pk_ses.100001.4cf6=*; __utma=30149280.1633528206.1506160772.1507283346.1507290433.3; __utmb=30149280.0.10.1507290433; __utmc=30149280; __utmz=30149280.1506160772.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utma=223695111.1475767059.1506160772.1507283346.1507290433.3; __utmb=223695111.0.10.1507290433; __utmc=223695111; __utmz=223695111.1506160772.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); push_noty_num=0; push_doumail_num=0',
            'Host': 'movie.douban.com',
            'Referer': 'https://movie.douban.com/top250?start=225&filter=',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36',
        }

    def run(self):
        self.parse_page()

    def send_request(self,url):
        '''
        用来发送请求的方法
        :return: 返回网页源码
        '''
        # 请求出错时,重复请求3次,
        i = 0
        while i <= 3:
            try:
                print u"[INFO]请求url:"+url
                html = requests.get(url=url,headers=self.headers).content
            except Exception as e:
                print u'[INFO] %s%s'% (e,url)
                i += 1
            else:
                return html

    def parse_page(self):
        '''
        解析网站源码,并采用xpath提取 电影名称和平分放到队列中
        :return:
        '''
        response = self.send_request(self.url)
        html = etree.HTML(response)
        # 获取到一页的电影数据
        node_list = html.xpath("//div[@class='info']")
        for move in node_list:
            # 电影名称
            title = move.xpath('.//a/span/text()')[0]
            # 评分
            score = move.xpath('.//div[@class="bd"]//span[@class="rating_num"]/text()')[0]

            # 将每一部电影的名称跟评分加入到队列
            self.q.put(score + "\t" + title)


def main():
    # 创建一个队列用来保存进程获取到的数据
    q = Queue()
    base_url = 'https://movie.douban.com/top250?start='
    # 构造所有url
    url_list = [base_url+str(num) for num in range(0,225+1,25)]

    # 保存线程
    Thread_list = []
    # 创建并启动线程
    for url in url_list:
        p = DouBanSpider(url,q)
        p.start()
        Thread_list.append(p)

    # 让主线程等待子线程执行完成
    for i in Thread_list:
        i.join()

    while not q.empty():
        print q.get()

if __name__=="__main__":

    start = time.time()
    main()
    print '[info]耗时:%s'%(time.time()-start)

  

 4858.com 14

 

 

行使协程爬取,耗费时间壹伍S,

4858.com 154858.com 16

#!/usr/bin/env python2
# -*- coding=utf-8 -*-

from Queue import Queue
import time
from lxml import etree
import requests
import gevent

# 打上猴子补丁
from gevent import monkey
monkey.patch_all()

class DouBanSpider(object):
    def __init__(self):
        # 创建一个队列用来保存进程获取到的数据
        self.q = Queue()
        self.headers = {
            'Cookie': 'll="118282"; bid=ctyiEarSLfw; ps=y; __yadk_uid=0Sr85yZ9d4bEeLKhv4w3695OFOPoedzC; dbcl2="155150959:OEu4dds1G1o"; as="https://sec.douban.com/b?r=https%3A%2F%2Fbook.douban.com%2F"; ck=fTrQ; _pk_id.100001.4cf6=c86baf05e448fb8d.1506160776.3.1507290432.1507283501.; _pk_ses.100001.4cf6=*; __utma=30149280.1633528206.1506160772.1507283346.1507290433.3; __utmb=30149280.0.10.1507290433; __utmc=30149280; __utmz=30149280.1506160772.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utma=223695111.1475767059.1506160772.1507283346.1507290433.3; __utmb=223695111.0.10.1507290433; __utmc=223695111; __utmz=223695111.1506160772.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); push_noty_num=0; push_doumail_num=0',
            'Host': 'movie.douban.com',
            'Referer': 'https://movie.douban.com/top250?start=225&filter=',
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.104 Safari/537.36',
        }

    def run(self,url):
        self.parse_page(url)

    def send_request(self,url):
        '''
        用来发送请求的方法
        :return: 返回网页源码
        '''
        # 请求出错时,重复请求3次,
        i = 0
        while i <= 3:
            try:
                print u"[INFO]请求url:"+url
                html = requests.get(url=url,headers=self.headers).content
            except Exception as e:
                print u'[INFO] %s%s'% (e,url)
                i += 1
            else:
                return html

    def parse_page(self,url):
        '''
        解析网站源码,并采用xpath提取 电影名称和平分放到队列中
        :return:
        '''
        response = self.send_request(url)
        html = etree.HTML(response)
        # 获取到一页的电影数据
        node_list = html.xpath("//div[@class='info']")
        for move in node_list:
            # 电影名称
            title = move.xpath('.//a/span/text()')[0]
            # 评分
            score = move.xpath('.//div[@class="bd"]//span[@class="rating_num"]/text()')[0]

            # 将每一部电影的名称跟评分加入到队列
            self.q.put(score + "\t" + title)


    def main(self):


        base_url = 'https://movie.douban.com/top250?start='
        # 构造所有url
        url_list = [base_url+str(num) for num in range(0,225+1,25)]
        # 创建协程并执行
        job_list = [gevent.spawn(self.run,url) for url in url_list]
        # 让线程等待所有任务完成,再继续执行。
        gevent.joinall(job_list)

        while not self.q.empty():
            print self.q.get()

if __name__=="__main__":
    start = time.time()
    douban = DouBanSpider()
    douban.main()
    print '[info]耗时:%s'%(time.time()-start)

gevent

 

 4858.com 17

 

 

用了多进程,二十四线程,协程,达成的代码都同样,未有测试出显明的老大好!都不分上下,大概跟互连网,可能服务器配置有关。

但辩驳上的电话线程,协程在I/O密集的操作品质是要压倒进程的。

 

也大概是本人的艺术有标题,还望大神们请教!

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有