一、进程(Process)
进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。
进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时,它才能成为一个活动的实体,我们称其为进程。
在Python中调用第三方模块multiprocessing,其过程就三步:
# 第一步:初始化multiprocess
# 第二步:start
# 第三步:join
import time
import multiprocessing
def process_run(params):
time.sleep(2)
print(params)
time.sleep(2)
print(params)
time.sleep(2)
print(params)
if __name__ == '__main__':
params = 'old food sleepy is going to sleep'
p = multiprocessing.Process(target=process_run, args=(params,)) # 实例化对象
p.start() # 开启进程
print('lyb is lyb')
p.join() # 关闭
print('lyb is lyb')
进程池:
使用multiprocessing模块提供的Pool
方法.
初始化Pool时,可以指定一个最大进程数,当有新的请求提交到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来执行,请看下面的实例:
import multiprocessing
import time
def process_run(params):
time.sleep(2)
print('tomato' + params)
time.sleep(2)
if __name__ == '__main__':
# 第一步
pool = multiprocessing.Pool(2)
for i in range(0, 10):
pool.apply_async(process_run, ('My English is very good' + str(i),))
# 第二步
pool.close()
# 第三步
pool.join()
二、线程(Thread)
通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程可以利用进程所拥有的资源,在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位,由于线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统多个程序间并发执行的程度。
线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮。
在Python中开启线程用模块threading里面的Thread类,也是三步走:
# 第一步:创建 threading的类
# 第一步:执行start
# 第一步:等待结束 join
import threading
import time
def th_run(params):
time.sleep(2)
print(params)
time.sleep(2)
if __name__ =='__main__':
params = 'black potato is a good boy'
# 创建Thread类, 传入两个参数
t = threading.Thread(target=th_run, args=(params,))
# 执行
t.start()
print('sunyang is good at swimming')
time.sleep(2)
print('sunyang is good at swimming')
time.sleep(2)
#等待结束
t.join()
线程池:
Python中线程池的创建用第三方库threadpool里面的ThreadPool类:(感觉不怎么常用)
import threadpool
import time
def thread_run(params, cuolechileni):
time.sleep(2)
print('tomato' + params + cuolechileni)
time.sleep(2)
# 有多少条thread
pool = threadpool.ThreadPool(2)
params = [(['我用java','aaa'], None),(['我用php', 'bbb'],None), (['我学区块链','ccc'], None), (['我学大数据', 'ddd'], None)]
# 创建函数和参数的类
requests = threadpool.makeRequests(thread_run, params)
for req in requests:
pool.putRequest(req)
print('lala 我们在这了,' + str(req))
pool.wait()
print('我才是最后的boss')
下面给出一个进程、进程池的应用实例:(爬取喜马拉雅音频文件),具体分析略
import requests
from lxml import etree
from urllib import request
import time, os
from multiprocessing import Queue, Pool, Process
def paqu(q):
page = 1
while page <= 4:
url1 = 'https://www.ximalaya.com/xiangsheng/9742789/p{}/'.format(page)
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'}
response = requests.get(url1, headers=headers)
res_html = response.text
res_lxml = etree.HTML(res_html)
res_href = res_lxml.xpath('//ul[@class="dOi2"]/li/div[2]/a/@href') # ['/xiangsheng/9742789/46430555', '/x0
# print(res_href)
for href1 in res_href:
href_one = request.urljoin(url1, href1) # https://www.ximalaya.com/xiangsheng/9742789/46105777
# print(href_one)
href_last = href_one.split('/')[-1] # 46430555
# print(href_last)
url2 = 'https://www.ximalaya.com/revision/play/tracks?trackIds={}'.format(href_last)
response_one = requests.get(url2, headers=headers)
json_dict = response_one.json()
# print(json_dict)
src_str = json_dict['data']['tracksForAudioPlay'][0]['src']
# print(src_str)
if os.path.exists('Download_mp3'):
pass
else:
os.mkdir('Download_mp3')
trackName = 'Download_mp3/' + json_dict['data']['tracksForAudioPlay'][0]['trackName']
# print(trackName)
q.put((src_str, trackName)) # ----------------
# request.urlretrieve(src_str, trackName + '.m4a')
print(page)
print('我是消息队列:', q.qsize())
page += 1
def write_mp3(mp3_url_referer_url):
time.sleep(5)
(src_str, trackName) = mp3_url_referer_url
print('开始下载', src_str, trackName)
# request.urlretrieve(src_str, trackName + '.m4a')
if __name__ == '__main__':
q = Queue()
p = Process(target=paqu, args=(q,))
p.start()
# 开启的进程数量
download_pool = Pool(5)
while True:
try:
mp3_url_referer_url = q.get() # 可以设置超时时间
print(mp3_url_referer_url)
download_pool.apply_async(write_mp3, (mp3_url_referer_url,))
except:
print('Queue is Empty!')
break
download_pool.close()
download_pool.join()
# 程序最后退出前进行join
p.join()