zoukankan      html  css  js  c++  java
  • Python的进程和线程(二)——IO密集型任务

    一、什么是IO密集型任务?

    主要的核心任务是进行IO操作,比如写文件,进行磁盘的读写等等。

    上一篇博客,对计算密集型任务,多线程并没有体现它的好处,反而话费的时间更长。对IO密集型任务多线程会有明显的优势

    二、举例:

    任务:爬取韩寒的博客

    1、获取urls,

    2、根据文章的url,爬取内容,保存文件

    3、将urls分给不同的进程/线程

    4、多进程/多线程爬取

    step1:爬取urls

    思路:用requests库来爬取页面,用beautifulSoup库来获取目标的urls值

    import requests
    from bs4 import BeautifulSoup
    
    def get_urls(url):
        '''
        获取目标URL
        :param url: 列表页面url
        :return: 目标url列表
        '''
        res=requests.get(url).text
        soup = BeautifulSoup(res, features="html.parser")
        #通过css selector解析页面,获取元素
        artile_urls=soup.select(".atc_title > a")
        url_list=list(i.get("href") for i in artile_urls)
        return(url_list)

    step2:根据文章的url,爬取内容,保存文件

    import time,os
    import requests
    from bs4 import BeautifulSoup
    
    def get_content(urls,dirpath):
        '''
        获取文章内容
        :param urls: 要获取文章的url列表
        :param dirpath: 文章内容文件保存路径
        :return: 
        '''
    
        for url in urls:
            # print("要抓取的url是%s" % url)
            res = requests.get(url).content.decode("utf-8")
    
            soup = BeautifulSoup(res, features="html.parser")
            paragraphs = soup.select("#sina_keyword_ad_area2 > p")
            content=""
            for i in paragraphs:
                content+=i.get_text()
            if not os.path.exists(dirpath):
                os.makedirs(dirpath)
            open(dirpath + r'/' + url[-26:], 'w').write(content)

    step3:将urls分给不同的进程/线程 

    思路:

      假设我们启动n个进程,一共要爬取的url列表是urls,列表的长度为url_len

      我们先把列表整除n得到长度为L(不一定能够整除,所以最后一个进程为总数-前面n-1个进程的),则第1个进程要爬取的url列表是urls[0:L],第2个进程要爬取的url列表是url[L: 2L],依次类推。。。。,最后一个进程要爬取的url列表是url[i*n:url_len]

        for n in [8, 4, 2, 1]:
            # 将urls分割到url_list
            url_list = []
            url_split_len = url_len // n
            for i in range(n):
                if i == n - 1:
                    url_list.append(urls[i * url_split_len:url_len])
                else:
                    url_list.append(urls[i * url_split_len:(i + 1) * url_split_len])
               

    参照上一篇博客,多进程和多线程函数。

    我们的目标函数是,get_content,这个函数需要2个参数,一个是url列表,一个是保存文件的路径

    import time
    
    def thread_process_job(n, Thread_or_Process, url_list, job):
        """
        n: 多线程或多进程数
        Thread_Process: Thread/Process类
        job: countdown任务
        """
        local_time = time.time()
    
        # 实例化多线程或多进程
        threads_or_processes = [Thread_or_Process(target=job, args=(url_list[j],str(n)+Thread_or_Process.__name__)) for j in range(n)]
        for t in threads_or_processes:
            t.start()  # 开始线程或进程,必须调用
        for t in threads_or_processes:
            t.join()  # 等待直到该线程或进程结束
        print(n, Thread_or_Process.__name__, " run job need ", time.time() - local_time)

     step4:多进程或者多线程爬取

    我们爬取前6页的数据,代码如下

    if __name__=="__main__":
        t = time.time()
    
        urls = []
        for i in range(7):
            url='http://blog.sina.com.cn/s/articlelist_1191258123_0_' + str(i + 1) + '.html'
            page_urls=get_urls(url)
            urls.extend(page_urls)
        url_len = len(urls)
        print("total urls number is ", url_len)
    
        for n in [8, 4, 2, 1]:
            # 将urls分割到url_list
            url_list = []
            url_split_len = url_len // n
            for i in range(n):
                if i == n - 1:
                    url_list.append(urls[i * url_split_len:url_len])
                else:
                    url_list.append(urls[i * url_split_len:(i + 1) * url_split_len])
            # 分割任务后创建线程
            thread_process_job(n, Thread, url_list, get_content)
            thread_process_job(n, Process, url_list, get_content)
    
        print("All done in ", time.time() - t)

    代码可能存在的问题:

    代码在运行中,可能会存在的问题是,调用get_content函数时,可能一个进程正在创建文件夹,一个进程正好在判断文件不存在要创建,在创建的时候会报错文件已存在。

  • 相关阅读:
    前端的貌似不顺道整个 小程序,不是那么回事哈
    sql server 大批数据插入时,时间过长的问题
    web api 权限控制
    推荐一个测试Web API, web service工具
    ConcurrentDictionary的用法
    Socket
    微信小程序(一)
    List常用几种方式
    c# 文件下载
    自定义身份验证
  • 原文地址:https://www.cnblogs.com/yimiaoyikan/p/10485207.html
Copyright © 2011-2022 走看看