25 - 线程池和指令系统

Day 25

一、线程等待(阻塞)

1.子线程对象.join

  • 可以阻塞当前线程进城,使其在完成指定线程之后在继续执行该线程
  • 示例:我想利用多线程下载三部电影,在电影全部下载完成之后在打印”全部下载完成“。
from threading import Thread
from time import sleep
from datetime import datetime
from random import randint



def download(name):
	print(f'{name}开始下载:{datetime()}')
	sleep(randint(2, 7))
	print(f'{name}下载完成:{datetime()}')


if __name__ == '__main__':

    t1 = Thread(target=download, args=('明日战纪',))
    t2 = Thread(target=download, args=('斗罗大陆',))
    t3 = Thread(target=download, args=('独行月球',))
# 示例1一:
    t1.start()
    t2.start()
    t3.start()

    # 1. 子线程对象.join()   -   阻塞当前线程直到指定子线程任务完成
    t1.join()
    t2.join()
    t3.join()
    print('==============全部下载完成!============')
    
# 示例2:前两个电影都下载完成后才下载第三个电影
    t1.start()
    t2.start()

    t1.join()
    t2.join()

    t3.start()
    t3.join()
    print('==============全部下载完成!============')

二、线程池

1.线程池工作原理

  • 线程池就是管理多个线程的工具
  • 先创建指定个数的线程,最后添加多个任务(任务数量>线程数量)让线程池中的线程去执行添加所有的任务,直到所有任务执行完成(线程池中的每个线程可能会多执行多个任务)
  • 在使用线程池的时候需要先导入相关模块
from threading import Thread, current_thread
from concurrent.futures import ThreadPoolExecutor
  • 示例:如我想下载1000部电影,我不会一个一个去创建子线程,遍可以调用线程池

2.线程池添加任务

  • 一次添加一个任务
  • 注意:实参的数量由前面的函数在调用的时候需要的实参来决定
    • 线程池.submit(函数, 实参1, 实参2, 实参3,…)
  • 同时添加多个任务
  • 注意:使用map添加多个任务的时候,任务对应的函数必须是有且只有一个参数的函数
    • 线程池.submit(函数, 实参1, 实参2, 实参3,…)
# 导入相关模块
from threading import Thread, current_thread
from time import sleep
from datetime import datetime
from random import randint
from concurrent.futures import ThreadPoolExecutor

f'{name}开始下载:{datetime.now()}', current_thread()
# 创建函数模拟下载电影
def download(name):
	print(f'{name}开始下载:{datetime.now()}', current_thread())
	sleep(randint(2, 7))
    print(f'{name}下载结束:{datetime.now()}')


# 开始下载电影
# 方案1:直接使用多线程下载1000个电影
if __name__ == '__main__':
    num = 0
    for _ in range(11):
 		# 创建空列表保存每一个子线程
 		ts = []
        for x in range(101):
            num += 1
            t = Thread(target=download, args=(f'电影{num}',))
            ts.append(t)
            t.start()
        # 循环调取每一个添加的子线程,直到全部运行结束,打印下载完成
        for x in ts:
            x.join()
        print('全部下载完成')



# 方案2:使用线程池下载1000个电影
if __name__ == '__main__':
	pool = ThreadPoolExecutor(3)
	# 一次添加一个任务: submit
	pool.submit(download, '肖生克的救赎')
    pool.submit(download, '霸王别姬')
    # 一次添加多个任务
    pool.map(download, ['V字仇杀队', '恐怖游轮', '沉默的羔羊'])

3.关闭线程池

  • 线程池关闭后无法再添加新的任务,并且会阻塞当前线程等待整个线程池的任务都完成
# 下载任务完成后,可以关闭线程池,等所有任务完成后打印结果
pool.shutdown()
    print('==============完成!=============')

练习:利用爬虫所学,爬取某网站数据,要求,使用线程池提高效率。

# 导入相关模块
import requests
from bs4 import BeautifulSoup
import csv
from concurrent.futures import ThreadPoolExecutor

# 创建访问函数
def get_nte_date(url:str):
    headers = {
        'user-agent':'Mozilla/4.0 (Windows NT 10.0; Win32; x64) AppleWebKit/522.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36'
    }
    response = requests.get(url, headers=headers)
    result = response.text
    # 直接调用解析函数
    analysis_data(result)

# 解析数据
def analysis_data(html:str):
    # 每一页数据以列表形式保存
    all_data = []
    # BeautifulSoup解析数据
    soup = BeautifulSoup(html,'lxml')
    all_div = soup.select('.grid_view>li>div.item')
    for div in all_div:
        rank = div.select_one('div.pic>em').text
        name = div.select_one('div.hd>a>span.title').text
        link = div.select_one('div.pic>a').attrs['href']
        info = div.select_one('.bd>p').text.strip().split('\n')[-1].strip()
        info_list = info.split('/')
        time = info_list[0]
        country = info_list[-2]
        category = info_list[-1]
        score = div.select_one('.rating_num').text
        comment_count = div.select('.star>span')[-1].text[:-3]
        intro_span = div.select_one('.inq')
        if intro_span:
            intro = intro_span.text
        else:
            intro = ''
        all_data.append([int(rank), name, link, score, time.strip(), country.strip(), category.strip(), comment_count, intro])
        # 将没页数据添加到总表
        films.append(all_data)


if __name__ == '__main__':
    # 创建总表保存每页数据
    films = []
    # 创建csv文件实现数据持久化
    f = open('file/豆瓣数据.csv', 'w', encoding='utf-8')
    writer = csv.writer(f)
    writer.writerow(['排名', '电影名称', '链接', '评分', '上映时间', '国家', '类型', '评论数', '简介'])
    # 使用线程池提高效率
    pool = ThreadPoolExecutor(10)
    for i in range(0, 251, 25):
        url = f'https://movie.douban.com/top250?start={i}&filter='
        pool.submit(get_nte_date, url)

    pool.shutdown()
    # 排序  利用列表比较原则
    films.sort()
    # 将数据写入文件
    for x in films:
        writer.writerows(x)
    # 保存文件
    f.close()

三、常用指令

执行指令的工具: Windows - 命令提示符(cmd) 、Mac - 终端

1. 运行python程序: - 运算程序的计算机必须先安装python环境

  • win: python py文件路径
  • mac: python3 py文件路径

2. 进入文件夹: cd

  • cd 文件夹相对路径、文件夹绝对路径
  • 注意:如果是windows操作系统,cd操作如果要跨盘需要先切盘,然后再cd
  • 切盘方法:C:、E:、D

3. 查看当前文件夹的内容

  • win: dir
  • Mac:ls

4. 用指令创建虚拟环境

  • 第一步:找到一个用来放虚拟环境的文件夹

  • 第二步:通过cd指令进入到存放虚拟环境的文件夹中

  • 第三步:创建虚拟环境

    • win: python -m venv 虚拟环境名
    • mac:python3 -m venv 虚拟环境名
  • 第四步:激活虚拟环境

    • (mac) source 虚拟环境目录/bin/activate
    • (windows) 虚拟环境目录\ Scripts\activate.bat
  • 第五步:退出虚拟环境 – deactivate

5.常用pip指令(pip - Python包管理工具)

  • pip list - 查看当前环境已经安装过的所有的第三方库
  • pip install 第三方库名称 - 下载并且安装指定的第三方库
  • pip install 第三方库名称 -i 镜像地址 - 在指定的镜像地址中下载安装
  • pip install 第三方库名称==版本号 -i 镜像地址
  • pip install 第三方库名称1 第三方库名称2
  • pip freeze > 依赖文件名 - 生成依赖文件
  • pip install -r 依赖文件路径 - 批量安装
  • pip uninstall 第三方库名称 - 卸载指定的第三方库
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值