Python课程设计 第 40 / 52 篇

线程并发-参考答案

Chapter23

任务名称 - 线程并发

打卡要求

  1. 写代码验证在多核CPU前提下对于IO密集型和计算密集型任务多进程和多线程的执行效率,要求如下:
1 执行效率使用time模块来完成
2 计算密集型可以用累加或者阶乘,在机器硬件允许的情况下,体现出时间的数量级
3 IO密集型可以用time来模拟,体现出时间的数量级
4 计算密集型分别用多进程和多线程实现
5 IO密集型也分别用多进程和多线程实现
"""
1 执行效率使用time模块来完成
2 计算密集型可以用累加或者阶乘,在机器硬件允许的情况下,体现出时间的数量级
3 IO密集型可以用time来模拟,体现出时间的数量级
4 计算密集型分别用多进程和多线程实现
5 IO密集型也分别用多进程和多线程实现
"""
import time
from multiprocessing import Process
from threading import Thread

def task1():
    """
    # 1 计算密集型任务
    :param:
    :return:
    """
    res = 1
    for i in range(1, 100000):
        res *= i

def task2():
    """
    2 I/O密集型多任务
    :param:
    :return:
    """
    time.sleep(3)

if __name__ == '__main__':
    time1 = time.time()
    p1 = Process(target=task1)
    p1.start()
    p1.join()
    print('计算密集型多进程:', time.time() - time1)

    time2 = time.time()
    t1 = Thread(target=task1)
    t1.start()
    t1.join()  # 同样是发信号,但是线程的开销小的多
    print('计算密集型多线程:', time.time() - time2)

    time3 = time.time()
    p1 = Process(target=task2)
    p1.start()
    p1.join()
    print('I/O密集型多进程:', time.time() - time3)

    time4 = time.time()
    t1 = Thread(target=task2)
    t1.start()
    t1.join()  # 同样是发信号,但是线程的开销小的多
    print('I/O密集型多线程:', time.time() - time4)

"""
执行结果:
    计算密集型多进程: 3.0727100372314453
    计算密集型多线程: 3.648629665374756
    I/O密集型多进程: 3.1356050968170166
    I/O密集型多线程: 3.0018515586853027
"""
  1. 写一个简易的爬虫程序,抓取博客园网站首页前10页中所有文章标题带有Python关键字(不区分大小写)的文章,并把文章链接和文章标题存入硬盘,要求如下:
1 使用正则表达式匹配出需要的数据,然后对数据进行解析
2 程序中很明显有多个任务,这多个任务必须是异步调用
3 任务的返回值要及时处理,不能等所有任务都执行完再统一处理
4 提示信息:可以使用生产者消费者模型来处理
5 尽可能提升程序的执行效率

爬虫储备知识:

requests模块是一个非常强大的爬虫模块,它的基本使用非常简单,但是它是所有爬虫程序的根源,我们只需要使用requests模块里面级简单的功能就能完成,用法可以通过查询得知。

"""
写一个简易的爬虫程序,抓取博客园网站首页前10页中所有文章标题带有
Python关键字(不区分大小写)的文章,并把文章链接和文章标题存入
硬盘,要求如下:
1 使用正则表达式匹配出需要的数据,然后对数据进行解析
2 程序中很明显有多个任务,这多个任务必须是异步调用
3 任务的返回值要及时处理,不能等所有任务都执行完再统一处理
4 提示信息:可以使用生产者消费者模型来处理
5 尽可能提升程序的执行效率
"""

# 基本思路与实现方案
import re
import time
import requests

t1 = time.time()

title_list = []
url = 'https://www.cnblogs.com/'
for i in range(1, 11):
    html = requests.post(url=url, data={"PageIndex": i}).text
    res = re.findall('<h3>.*?ython.*?</h3>', html)
    for j in res:
        title_list.append(j)

print(time.time() - t1)

# 异步思路与优化处理
import re
import requests
from concurrent.futures import ThreadPoolExecutor
import time

def catch(page):
    title_list = []
    url = 'https://www.cnblogs.com/'
    html = requests.post(url=url, data={"PageIndex": page}).text
    res = re.findall('<h3>.*?ython.*?</h3>', html)
    for j in res:
        title_list.append(j)

    return title_list

def analyze(obj):
    data = obj.result()
    if data:
        for j in data:
            res = j.split("=")
            link = res[2][1:-8]
            title = res[3][9:-9]
            with open('data.txt', mode='a', encoding='utf-8') as f:
                f.write('%s|%s\n' % (title, link))

if __name__ == '__main__':
    t1 = time.time()
    tp = ThreadPoolExecutor(10)
    for i in range(1, 11):
        tp.submit(catch, i).add_done_callback(analyze)
    print(time.time() - t1)

3. 使用线程Event写一个监测服务端机器服务状态的程序,要求如下:

1 模拟服务端机器5秒延迟,客户端每次等待时间为1秒
2 当用户等待三次还不能开始连接,就返回给用户一个提示信息
"""
使用线程Event写一个监测服务端机器服务状态的程序,要求如下:
1 模拟服务端机器5秒延迟,客户端每次等待时间为1秒
2 当用户等待三次还不能开始连接,就返回给用户一个提示信息
"""

from threading import Event, current_thread, Thread
import time

event = Event()

def check():
    print('%s 正在检测服务是否正常....' % current_thread().name)
    time.sleep(5)
    event.set()

def connect():
    print('%s 等待连接...' % current_thread().name)
    for _ in range(3):
        event.wait(2)
        if event.is_set():
            print('%s 开始连接...' % current_thread().name)
    if not event.is_set():
        print('网络异常')

if __name__ == '__main__':
    t1 = Thread(target=connect)
    t2 = Thread(target=connect)
    t3 = Thread(target=connect)
    c1 = Thread(target=check)
    t1.start()
    t2.start()
    t3.start()
    c1.start()