python 25 线程池和指令系统
一、线程等待
子线程 . join( ) — 阻塞当前线程直到指定线程任务完成。
from threading import Thread #导入线程
from time import sleep #导入等待时间
from datetime import datetime #到时日期时间
from random import randint #导入随机数
def download(name):
print(f'{name}开始下载:{datetime.now}')
sleep(randint(2,7)) #
print(f'{name}下载结束:{datetime.now}')
if __name__ == '__main__':
t1 = Thread(target=download,args=('明日战绩',))
t2 = Thread(target=download, args=('斗罗大陆',))
t3 = Thread(target=download, args=('独行月球',))
t1.start()
t2.start()
t3.start()
#1.子线程对象.join() - 阻塞当前线程直到指定线程任务完成
t1.join()
t2.join()
t3.join()
print('==============下载结束===============')
import requests
from bs4 import BeautifulSoup
import csv
from concurrent.futures import ThreadPoolExecutor
def get_net_data(url: str):
headers = {
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36'
}
proxies = {
'http': '121.206.253.171:4512',
'https': '121.206.253.171:4512'
}
response = requests.get(url, headers=headers, proxies=proxies)
# return response.text
analysis_data(response.text)
def analysis_data(html: str):
# 解析数据
soup = BeautifulSoup(html, 'lxml')
all_film_div = soup.select('.grid_view>li>.item')
all_data = [] #保存每一页所有电影
for div in all_film_div:
rank = div.select_one('.pic>em').text
name = div.select_one('.title').text
info = div.select_one('.bd>p').text.strip().split('\n')[-1].strip()
# time, country, category = info.split('/')
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, score, time.strip(), country.strip(), category.strip(), comment_count, intro])
films.append(all_data)
# print(all_data)
# writer.writerows(all_data)
if __name__ == '__main__':
films = [] #保存所有列表
f = open('file/电影.csv', 'w', encoding='utf-8', newline='')
writer = csv.writer(f)
writer.writerow(['排名', '电影名称', '评分', '上映时间', '国家', '类型', '评论数', '简介'])
pool = ThreadPoolExecutor(10)
for page in range(0, 251, 25):
url = f'https://movie.douban.com/top250?start={page}&filter='
pool.submit(get_net_data, url)
pool.shutdown()
# films.sort(key=lambda item:item[0][0])
films.sort()
for x in films:
writer.writerows(x)
二、线程池
线程池是管理多个线程的工具
- 线程池工作原理
先提前创建指定个数的线程,然后添加多个任务(任务数量>线程数量),让线程池中的线程去执行添加的所有任务,直到所有的任务都执行完(线程池中的每个线程都可能会执行多个任务)
2.1 创建线程池
ThreadPoolExecutor 创建线程池最大的值,注意,当线程很多的时候,只会创建3个线程
pool = ThreadPoolExecutor(100)
2.2 添加任务
线程池添加任务方式
方式1:一次添加一个任务 ---- submit(函数,实参1,实参2,实参3,…)
- 注意:实参的数量由前面的函数在调用的时候,需要的实参来决定
方式2 :同时提交多个任务 ---- map(函数,参数序列)
-
注意:使用map添加多个任务的时候,任务对应的函数,必须是有且只有一个参数对应的函数。
2.3 关闭线程池
线程池关闭后无法添加新的任务,并且hi阻塞当前线程等待整个线程池的任务完成。
pool . shutdown()
-
案例:使用多线程下载1000个电影
方案1 :直接使用多线程下载1000个电影
from threading import Thread,current_thread #current_thread 当前线程 from time import sleep from datetime import datetime from concurrent.futures import ThreadPoolExecutor def download(name): print(f'{name}开始下载:{datetime.now()}',current_thread()) sleep(2) print(f'{name}下载结束:{datetime.now()}') if __name__ == '__main__': num = 0 for _ in range(4): ts = [] for x in range(5): num += 1 t = Thread(target=download,args=(f'电影{num}',)) ts.append(t) t.start() for x in ts: x.join() ### 结果显示 电影1开始下载:2022-08-19 21:50:59.406115 <Thread(Thread-1, started 269528)> 电影2开始下载:2022-08-19 21:50:59.407115 <Thread(Thread-2, started 272252)> 电影3开始下载:2022-08-19 21:50:59.407115 <Thread(Thread-3, started 262944)> 电影4开始下载:2022-08-19 21:50:59.407115 <Thread(Thread-4, started 230448)> 电影5开始下载:2022-08-19 21:50:59.407115 <Thread(Thread-5, started 268964)> 电影2下载结束:2022-08-19 21:51:01.418595 电影1下载结束:2022-08-19 21:51:01.418595 电影5下载结束:2022-08-19 21:51:01.418595 电影4下载结束:2022-08-19 21:51:01.418595 电影3下载结束:2022-08-19 21:51:01.418595 电影6开始下载:2022-08-19 21:51:01.419584 <Thread(Thread-6, started 168460)> 电影7开始下载:2022-08-19 21:51:01.419584 <Thread(Thread-7, started 262512)> 电影8开始下载:2022-08-19 21:51:01.419584 <Thread(Thread-8, started 234984)> 电影9开始下载:2022-08-19 21:51:01.419584 <Thread(Thread-9, started 266792)> 电影10开始下载:2022-08-19 21:51:01.420589 <Thread(Thread-10, started 269140)> 电影9下载结束:2022-08-19 21:51:03.432116电影6下载结束:2022-08-19 21:51:03.432116电影8下载结束:2022-08-19 21:51:03.432116 电影10下载结束:2022-08-19 21:51:03.432116电影7下载结束:2022-08-19 21:51:03.432116 电影11开始下载:2022-08-19 21:51:03.433103 <Thread(Thread-11, started 267220)> 电影12开始下载:2022-08-19 21:51:03.433103 <Thread(Thread-12, started 271940)> 电影13开始下载:2022-08-19 21:51:03.433103 <Thread(Thread-13, started 271916)> 电影14开始下载:2022-08-19 21:51:03.433103 <Thread(Thread-14, started 269500)> 电影15开始下载:2022-08-19 21:51:03.434104 <Thread(Thread-15, started 250592)> 电影14下载结束:2022-08-19 21:51:05.444016 电影12下载结束:2022-08-19 21:51:05.444016 电影11下载结束:2022-08-19 21:51:05.444016 电影13下载结束:2022-08-19 21:51:05.444016 电影15下载结束:2022-08-19 21:51:05.444016 电影16开始下载:2022-08-19 21:51:05.444016 <Thread(Thread-16, started 244804)> 电影17开始下载:2022-08-19 21:51:05.445018 <Thread(Thread-17, started 271268)> 电影18开始下载:2022-08-19 21:51:05.445018 <Thread(Thread-18, started 264772)> 电影19开始下载:2022-08-19 21:51:05.445018 <Thread(Thread-19, started 267192)> 电影20开始下载:2022-08-19 21:51:05.445018 <Thread(Thread-20, started 270920)> 电影16下载结束:2022-08-19 21:51:07.453546电影20下载结束:2022-08-19 21:51:07.453546电影19下载结束:2022-08-19 21:51:07.453546电影17下载结束:2022-08-19 21:51:07.453546 电影18下载结束:2022-08-19 21:51:07.453546 ===============完成==================
方案2:使用线程池下载1000个电影
from threading import Thread,current_thread #current_thread 当前线程
from time import sleep
from datetime import datetime
from concurrent.futures import ThreadPoolExecutor
def download(name):
print(f'{name}开始下载:{datetime.now()}',current_thread())
sleep(2)
print(f'{name}下载结束:{datetime.now()}')
if __name__ == '__main__':
# 1. 创建线程池
#ThreadPoolExecutor 创建线程池最大的值,注意,当线程很多的时候,只会创建3个线程
pool = ThreadPoolExecutor(100)
# 2.添加任务
# 1)一次添加一个任务:submit(函数,实参1,实参2,实参3,...)
#注意:实参的数量由前面的函数在调用的时候,需要的实参来决定
pool.submit(download,'肖申克救赎')
pool.submit(download, '霸王别姬')
# 2)同时提交多个任务:map(函数,参数序列)
# 注意:使用map添加多个任务的时候,任务对应的函数,必须是有且只有一个参数对应的函数
pool.map(download,['三傻大闹好莱坞','星际穿越','沉默的羔羊','天天'])
# 3 .关闭线程池
# 线程池关闭后无法再添加新的任务,并且会阻塞当前线程等待整个线程池的任务完成
pool.shutdown()
print('===============完成==================')
### 结果显示
肖申克救赎开始下载:2022-08-19 21:55:34.872562 <Thread(ThreadPoolExecutor-0_0, started daemon 271484)>
霸王别姬开始下载:2022-08-19 21:55:34.873562 <Thread(ThreadPoolExecutor-0_1, started daemon 271996)>
三傻大闹好莱坞开始下载:2022-08-19 21:55:34.873562 <Thread(ThreadPoolExecutor-0_2, started daemon 252524)>
星际穿越开始下载:2022-08-19 21:55:34.874561 <Thread(ThreadPoolExecutor-0_3, started daemon 271944)>
沉默的羔羊开始下载:2022-08-19 21:55:34.874561 <Thread(ThreadPoolExecutor-0_4, started daemon 266488)>
天天开始下载:2022-08-19 21:55:34.874561 <Thread(ThreadPoolExecutor-0_5, started daemon 271904)>
天天下载结束:2022-08-19 21:55:36.880033沉默的羔羊下载结束:2022-08-19 21:55:36.880033霸王别姬下载结束:2022-08-19 21:55:36.880033
肖申克救赎下载结束:2022-08-19 21:55:36.880033
三傻大闹好莱坞下载结束:2022-08-19 21:55:36.880033
星际穿越下载结束:2022-08-19 21:55:36.880033
===============完成==================
三、指令操作
常见的指令操作
3.1 执行指令的工具:
-
Windows - 命令提示符(cmd) 、Mac - 终端
-
运行python程序: - 运算程序的计算机必须先安装python环境
-
win: python py文件路径
mac: python3 py文件路径
3.2 进入文件夹: cd
- cd 文件夹相对路径、文件夹绝对路径
- 注意:如果是windows操作系统,cd操作
- 如果要跨盘需要先切盘,然后再cd
- 切盘方法:C:、E:、D:
- 查看当前文件夹的内容
win: dir
Mac:ls
3.3 用指令创建虚拟环境
第一步:找到一个用来放虚拟环境的文件夹
第二步:通过cd指令进入到存放虚拟环境的文件夹中
第三步:创建虚拟环境
python -m venv 虚拟环境名
python3 -m venv 虚拟环境名
第四步:激活虚拟环境
(mac) source 虚拟环境目录/bin/activate
(windows) 虚拟环境目录\ Scripts\activate.bat
第五步:退出虚拟环境
deactivate
3.4 常用pip指令(pip - Python包管理工具)
- pip list - 查看当前环境已经安装过的所有的第三方库
- pip install 第三方库名称 - 下载并且安装指定的第三方库
- pip install 第三方库名称 -i 镜像地址 - 在指定的镜像地址中下载安装
- pip install 第三方库名称==版本号 -i 镜像地址
- pip install 第三方库名称1 第三方库名称2
- pip freeze > 依赖文件名 - 生成依赖文件
pip install -r 依赖文件路径 - 批量安装 - pip uninstall 第三方库名称 - 卸载指定的第三方库