多线程和多进程
01 . 什么是线程和进程
-
什么是进程 - 工厂
- 一个正在运行的应用程序就是一个进程。
- 每一个进程均运行在其钻用且受保护的内存(运行内存)中
-
什么是线程 - 工人
- 线程就是进程执行任务的基本单位,进程要做什么事情,必须要与线程。
-
线程的特点 - 串行
- 如果在一个线程中执行多个任务,任务是串行执行的(一个一个的按照顺序执行)
-
多线程
- 默认情况下,一个进程只有一个线程,多线程指的是在一个进程中有多个线程。
- 多线程执行不同的任务可以并行(同时)执行。
- 注意:多线程可以提高程序执行效率,但并不是越多越好(计算机一般的应用程序不要超过100个,爬虫可以达到200-300个)
02 . 多线程
-
主线程和子线程
-
一个进程默认只有一个线程,这个进程叫主线程。除了主线程以外的线程叫子线程。
-
如果进程中需要子线程,只能自己创建(创建线程类或者线程类的子类对象)
from threading import Thread,current_thread print(current_thread()) # <_MainThread(MainThread, started 6448)>
-
-
单线程的串行
def download(name): print(f'{name}开始下载:{datetime.now()}') time.sleep(2) print(f'{name}开始结束:{datetime.now()}') download('123') download('456') download('789')
-
创建三个子线程,下载散步电影
-
创建线程对象,并且分配线程任务:Thread(*,target,args)
target - 需要在子线程中调用的函数,需要给一个普通函数的函数名(代表任务)。
args - 在子线程中调用target对应的函数的时候需要的参数对应的元组。如果需要一个实参,元组就给一个元素,如果需要两个实参,元组就给两个元素…
-
启动线程:线程对象 . start()
import time from threading import Thread,current_thread from datetime import datetime # print(current_thread()) def download(name): print(f'{name}开始下载:{datetime.now()}') time.sleep(2) print(f'{name}开始结束:{datetime.now()}') # download('123') # download('456') # download('789') t = Thread(target=download,args=('123',)) t1 = Thread(target=download,args=('456',)) t2 = Thread(target=download,args=('789',)) t.start() t1.start() t2.start()
-
03 . 图虫图片一步下载
from selenium.webdriver import Chrome
import time
from lxml import etree
from threading import Thread
import requests
import os
from datetime import datetime
b = Chrome()
def download_image(url):
print(f'开始下载.....:{datetime.now()}')
res = requests.get(url)
image_name = os.path.basename(url)
open(f'files/{image_name}', 'wb').write(res.content)
print(f'图片下载完成!{datetime.now()}')
def get_html():
# 1. 获取图片地址
b.get('https://stock.tuchong.com/topic?topicId=50346')
time.sleep(1)
html = etree.HTML(b.page_source)
result = html.xpath('//div[@class="justified-layout"]/div/div/@data-lazy-url')
# 2. 下载图片
print('==================开始下载===================')
for img_url in result:
t = Thread(target=download_image, args=('https:'+img_url,))
t.start()
if __name__ == '__main__':
get_html()
04 . 线程阻塞
-
阻塞线程 - 等到某个线程的任务结束才接着执行
-
线程对象 . join()
import time from threading import Thread,current_thread from datetime import datetime from random import randint def download(name): print(f'{name}开始下载:{datetime.now()}') time.sleep(randint(2,10)) print(f'{name}下载结束:{datetime.now()}') t = Thread(target=download,args=('123',)) t1 = Thread(target=download,args=('456',)) t2 = Thread(target=download,args=('789',)) # 需求1:等到电影全部下载完成(三个线程都结束)才开始打印 # t.start() # t1.start() # t2.start() # t.join() # t1.join() # t2.join() # print('=======电影全部下载完成========') # 需求2:第一个电影下载完成后才开始下载2、3个电影 t.start() t.join() t1.start() t2.start() =========================华丽的分割线=============================== names = ['肖申克的救赎', '触不可及', '头脑特工队', '恐怖游轮'] ts = [] for name in names: t = Thread(target=download, args=(name,)) t.start() ts.append(t) for t in ts: t.join() # 要求: 所有电影都下载结束打印 '全部下载完成' print('=============全部下载完成=============')
05 . 多进程
-
多进程
- 一个应用程序默认只有一个进程(主进程),每一个进程中默认有一个线程(主线程)
- 一个程序可以有多个进程(除了主进程以外的进程叫子进程),任何一个进程中可以有多个线程
- 如果希望程序中有子进程,需要自己创建进程对象(创建的进程中都自带一个线程)
-
使用多进程
-
创建进程对象
-
启动进程
-
进程阻塞
def download(name): print(f'{name}开始下载:{datetime.now()}') time.sleep(2) print(f'{name}下载结束:{datetime.now()}') # 注意:如果想要使用多进程,必须在程序中添加这个if语句 if __name__ == '__main__': # 1)创建进程对象 p1 = Process(target=download, args=('肖生克的救赎',)) p2 = Process(target=download, args=('惊魂记',)) p3 = Process(target=download, args=('7号房的礼物',)) # 2)启动进程 p1.start() p2.start() p3.start() # 3)进程阻塞 p1.join() p2.join() p3.join() print('下载完成!')
-