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函数时,可能一个进程正在创建文件夹,一个进程正好在判断文件不存在要创建,在创建的时候会报错文件已存在。

原文地址:https://www.cnblogs.com/yimiaoyikan/p/10485207.html

时间: 2024-11-05 03:09:18

Python的进程和线程(二)——IO密集型任务的相关文章

python之进程、线程、协程的调度原理

进程.线程和协程的调度和运行原理总结. 进程.线程的调度策略介绍 linux的操作系统详细调度策略可参考:http://blog.csdn.net/gatieme/article/details/51872659 linux中的进程主要有三种调度策略: 优先级调度:将进程分为普通进程和实时进程: 先进先出(队列)调度:实时进程先创建的先执行,直到 轮转调度(时间片):达到一定的CPU执行时间后强制切换: 多进程程序的调度其实还是线程的调度,线程才是CPU调度的基本单位:在同一个进程内线程切换不会

《Python》进程收尾线程初识

from multiprocessing import Manager 把所有实现了数据共享的比较便捷的类都重新又封装了一遍,并且在原有的multiprocessing基础上增加了新的机制list.dict 机制:支持的数据类型非常有限 list.dict都不是数据安全的,需要自己加锁来保证数据安全 from multiprocessing import Manager,Process,Lock def work(d,lock): with lock: d['count'] -= 1 if __

Python(十) 进程、线程、协程篇

本节内容 1.操作系统发展史    2.进程.与线程区别    3.Python GIL全局解释器锁    4.线程        1.语法        2.join        3.线程锁 Lock.RLock.信号量        4.将线程变为守护进程        5.Event事件        6.queue队列        7.生产者消费者模型        8.Queue队列        9.开发一个线程池    5.进程        1.语法        2.进程间

python的进程与线程

一.进程与线程的相关概念 1.什么是进程 进程是一个程序在一个数据集上的一次动态执行过程. 进程一般由程序,数据集,进程控制块三部分组成. 2.什么是线程 线程也叫轻量级进程,它是一个基本的CPU执行单元,也是程序执行过程中的最小单元,由线程ID.程序计数器.寄存器集合和堆栈共同组成.线程的引入减小了程序并发执行时的开销,提高了操作系统的并发性能.线程没有自己的系统资源. 3.线程与进程的关系 线程不能独立存在,一个线程肯定有一个父进程.进程也不能独立存在,它一定也包含一个进程.可以理解为进程是

python之进程,线程,协程简单理解

进程:资源单位,由操作系统控制调度.正在执行的一个程序或者过程,进程之间不共享资源,进程间通讯手段:管道,队列,信号量等.多用于计算密集型场景,如金融计算 线程:是cpu的最小执行单位,由操作系统控制调度.一个进程至少有一个线程,同一个进程里面的多个线程共享该进程的内存资源(此处会涉及到资源的抢夺),因此需要用到“锁”,来防止资源争抢而导致的死锁等问题,创建线程的开销远远小于创建进程的开销.适用场景:IO密集型,如socket. 协程:实现单线程的并发,由用户自己通过程序来实现控制调度.修改共享

【Python】进程和线程

多任务的实现方式有三种方式: 1.多进程 2.多线程 3.多进程+多线程(这种比较复杂,实际很少采用) [多进程] 1.在mac中创建子进程使用Python封装的fork()系统调用. import os pid = os.fork() pid 2.在windows上的实现. 使用multiprocessing模块的Process类. 为了观察,还加了一下端代码~ # -*- coding: utf-8 -*- from multiprocessing import Process import

Python下进程与线程的原理及区别

对于所有的语言都可能会遇到进程和线程的问题,一般情况下线程是由进程产生的,一个进程产生多个线程来按照一定的规则(Python下根据CPU调度算法和全局进程锁)来利用CPU,我们称之为多线程模式:而一个进程在产生的同时,同时会生成一个主线程,如果程序生成多个进程,那么每个进程都会产生一个线程,多个程序按照一定的规则去利用CPU,我们称之为多进程模式.                 Python下多线程与多进程关系图原理如下所示:

Python之进程与线程

一.进程 1.什么是进程 程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程.程序和进程的区别就在于:程序是指令的集合,它是进程运行的静态描述文本:进程是程序的一次执行活动,属于动态概念. 在多道编程中,我们允许多个程序同时加载到内存中,在操作系统的调度下,可以实现并发地执行.这是这样的设计,大大提高了CPU的利用率.进程的出现让每个用户感觉到自己独享CPU,因此,进程就是为了在CPU上实现多道编程而提出的. 2.有了进程为什么还要线程? 进程有很

Python之进程、线程、协程篇

本章内容: 线程(线程锁.threading.Event.queue 队列.生产者消费者模型.自定义线程池) 进程(数据共享.进程池) 协程 线程 Threading用于提供线程相关的操作.线程是应用程序中工作的最小单元,它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务. threading 模块建立在 _thread 模块之上.thread 模块以低级.原始的方式来处理和控制线程,而 threading