python爬虫进程和线程的区别_Python爬虫 | 多线程、多进程、协程
对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程,打开一个Word就启动了一个Word进程。
有些进程还不止同时干一件事,比如Word,它可以同时进行打字、拼写检查、打印等事情。在一个进程内部,要同时干多件事,就需要同时运行多个“子任务”,我们把进程内的这些“子任务”称为线程(Thread)。
进程、线程、协程的区别
多进程模式最大的优点就是稳定性高,因为一个子进程崩溃了,不会影响主进程和其他子进程。(当然主进程挂了所有进程就全挂了,但是Master进程只负责分配任务,挂掉的概率低)著名的Apache最早就是采用多进程模式。
多进程模式的缺点是创建进程的代价大,在Unix/Linux系统下,用fork调用还行,在Windows下创建进程开销巨大。另外,操作系统能同时运行的进程数也是有限的,在内存和CPU的限制下,如果有几千个进程同时运行,操作系统连调度都会成问题。
多线程模式通常比多进程快一点,但是也快不到哪去,而且,多线程模式致命的缺点就是任何一个线程挂掉都可能直接造成整个进程崩溃,因为所有线程共享进程的内存。
协程的优势:
最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。
第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。
一、多进程
Case 01
# 多进程,使用Pool
from multiprocessing importPool
deff(x):
return x*x
if __name__ =='__main__':
p = Pool(5)
list = [1,2,3,4,5,6,7,8,9]
print(p.map(f,list)) # map是做映射
输出:[1, 4, 9, 16, 25, 36, 49, 64, 81]
Case01-1
# 多进程,使用Pool
importtime
importrequests
from multiprocessing importPool
task_list =[
'http://bj.maitian.cn/zfall/PG1',
'http://bj.maitian.cn/zfall/PG2',
'http://bj.maitian.cn/zfall/PG3',
'http://bj.maitian.cn/zfall/PG4',
'http://bj.maitian.cn/zfall/PG5',
'http://bj.maitian.cn/zfall/PG6',
'http://bj.maitian.cn/zfall/PG7',
'http://bj.maitian.cn/zfall/PG8',
'http://bj.maitian.cn/zfall/PG9',
'http://bj.maitian.cn/zfall/PG10',
]
header ={
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'}
defdownload(url):
response =requests.get(url,
headers=header,
timeout=30)
returnresponse.status_code
if __name__ == '__main__':
p = Pool(10)
time_old =time.time()
for item inp.map(download, task_list):
print(item)
time_new =time.time()
time_cost = time_new -time_old
print(time_cost)
Case 02
# 多进程,使用Process对象
from multiprocessing importProcess
deff(name):
print('hello',name)
if __name__ == '__main__':
p_1 = Process(target=f, args=('bob',)) # 注意:参数是只包含一个元素的元祖
p_1.start()
p_1.join()
p_2 = Process(target=f, args=('alice',))
p_2.start()
p_2.join()
输出:
hello bob
hello alice
Case02-1
# 多进程,使用Process对象
importtime
importrequests
from multiprocessing importProcess
task_list =[
'http://bj.maitian.cn/zfall/PG1',
'http://bj.maitian.cn/zfall/PG2',
'http://bj.maitian.cn/zfall/PG3',
'http://bj.maitian.cn/zfall/PG4',
'http://bj.maitian.cn/zfall/PG5',
]
header ={
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'}
defdownload(url):
response =requests.get(url,
headers=header,
timeout=30)
print(response.status_code)
if __name__ == '__main__':
for item intask_list:
p = Process(target=download, args=(item,))
p.start()
p.join()
二、多线程
Case 01
importthreading
importtime
classmyThread(threading.Thread):
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self)
self.threadID =threadID
self.name =name
self.counter =counter
defrun(self):
print("Starting " +self.name)
# 获得锁,成功获得锁定后返回True
# 可选的timeout参数不填时将一直阻塞直到获得锁定
# 否则超时后将返回False
threadLock.acquire()
print_time(self.name, self.counter, 3)
# 释放锁
threadLock.release()
defprint_time(threadName, delay, counter):
whilecounter:
time.sleep(delay)
print("%s: %s" %(threadName, time.ctime(time.time())))
counter -= 1threadLock =threading.Lock()
threads =[]
# 创建新线程
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
# 开启新线程
thread1.start()
thread2.start()
# 添加线程到线程列表
threads.append(thread1)
threads.append(thread2)
# 等待所有线程完成
for t inthreads:
t.join()
print("Exiting Main Thread")
Case 02
importthreadpool
importtime
defsayhello (a):
print("hello: "+a)
time.sleep(2)
defmain():
globalresult
seed=["a","b","c"]
start=time.time()
task_pool=threadpool.ThreadPool(5)
requests=threadpool.makeRequests(sayhello,seed)
for req inrequests:
task_pool.putRequest(req)
task_pool.wait()
end=time.time()
time_m = end-start
print("time: "+str(time_m))
start1=time.time()
for each inseed:
sayhello(each)
end1=time.time()
print("time1: "+str(end1-start1))
if __name__ == '__main__':
main()
Case 03
from concurrent.futures importThreadPoolExecutor
importtime
defsayhello(a):
print("hello: "+a)
time.sleep(2)
defmain():
seed=["a","b","c"]
start1=time.time()
for each inseed:
sayhello(each)
end1=time.time()
print("time1: "+str(end1-start1))
start2=time.time()
with ThreadPoolExecutor(3) as executor:
for each inseed:
executor.submit(sayhello,each)
end2=time.time()
print("time2: "+str(end2-start2))
start3=time.time()
with ThreadPoolExecutor(3) as executor1:
executor1.map(sayhello,seed)
end3=time.time()
print("time3: "+str(end3-start3))
if __name__ == '__main__':
main()
多线程做爬虫,如果有一个线程出现问题,所有的都失败了。所以,不适合做爬虫。
三、协程
Case 01Client example:await, 等待某某执行完成以后才执行下一步
importaiohttp
importasyncio
async deffetch(session, url):
async with session.get(url,) as response:
return await response.text() # 注意text加括号了
async defmain():
async with aiohttp.ClientSession() as session: # 使用aiohttp库里的ClientSession()函数创建一个session对象
html = await fetch(session, 'http://www.baidu.com') # 想要使用异步函数fetch的返回结果,必须加await参数,意思是必须等它执行完毕,才会去取它的返回值
print(html)
loop = asyncio.get_event_loop() # 获取EventLoop
loop.run_until_complete(main()) # 执行coroutine
Case通过gather实现并发,sleep,是暂时睡,把CPU给其他任务
通过gather方法实现并发.gather除了多任务外,还可以对任务进行分组。优先使用gather.
gather的意思是「搜集」,也就是能够收集协程的结果,而且要注意,它会按输入协程的顺序保存的对应协程的执行结果。
#coding:utf-8
importasyncio
async defa(t):
print('-->', t)
await asyncio.sleep(0.5) # 暂停0.5秒,在这期间把CPU让给其他协程,可以让其他协程去执行
print('
return t * 10
defmain():
futs = [a(t) for t in range(6)] # 列表生成式
print(futs) # coroutine object 协程对象
ret = asyncio.gather(*futs) #记得加 *
print(ret) # <_gatheringfuture pending> 收集未来对象
loop =asyncio.get_event_loop()
ret1 =loop.run_until_complete(ret)
print(ret1)
main()
Case03loop.create_task比gather方法使用的更普遍一些,loop.create_task让任务开始执行
#coding:utf-8
importasyncio
async defa(t):
print('-->', t)
await asyncio.sleep(0.5) # 这里睡0.5s
print('
return t * 10async defb():
# loop = asyncio.get_event_loop()
cnt =0
while 1: # 死循环,无限执行下去
cnt += 1 # counter计数器的缩写
cor = a(cnt) # coroutine
resp =loop.create_task(cor)
await asyncio.sleep(0.1) # 睡的过程中,a 函数就可以执行。先执行a(1),睡0.1s;再执行a(2),睡0.1s;再执行,执行到a(5)时,用时0.5s
print(resp)
loop =asyncio.get_event_loop()
loop.run_until_complete(b())
参考:
Python的线程与进程
Python的全局解释器锁(GIL)
Python分布式计算
深入理解Python异步编程(上) - 简书
Awesome Asyncio 《碉堡的Asyncio·中文版》 - 简书
Kotlin Coroutines(协程) 完全解析(一),协程简介 - 简书 携程系列文章
Aiohttp相关博客
Welcome to AIOHTTP — aiohttp 3.5.4 documentation
https://www.cnblogs.com/shijieli/p/10826743.html
python爬虫进程和线程的区别_Python爬虫 | 多线程、多进程、协程相关推荐
- Python 多线程 多进程 协程 yield
python中多线程和多进程的最大区别是稳定性和效率问题 多进程互相之间不影响,一个崩溃了不影响其他进程,稳定性高 多线程因为都在同一进程里,一个线程崩溃了整个进程都完蛋 多进程对系统资源开销大,多线 ...
- python爬虫进程和线程的区别_熬了两个通宵写的!终于把多线程和多进程彻底讲明白了!...
我们知道,在一台计算机中,我们可以同时打开许多软件,比如同时浏览网页.听音乐.打字等等,看似非常正常.但仔细想想,为什么计算机可以做到这么多软件同时运行呢?这就涉及到计算机中的两个重要概念:多进程和多 ...
- 多线程多进程协程的区别和不同的应用场景
当然既然是都是 多这个字开头,那么就是多任务,我们需要了解 并发:指的是任务数多余cpu核数,通过操作系统的各种任务调度算法, 实现⽤多个任务"⼀起"执⾏(实际上总有⼀些任务不在执 ...
- python进程线程协程区别_Python3多线程与协程
python中的多线程非常的常用,之前一直糊里糊涂地使用,没有一些系统性的概念,记录一下~ 0x001 多线程的优势:可将长时间占用的程序放到后台 可能会加速程序执行速度 能够实现一些类似同步执行的效 ...
- 进程和线程的区别, 面相对象补充, 进程, 数据共享, 锁, 进程池, 爬虫模块(requests, bs4(beautifulsoup))...
一. 进程和线程的区别? 第一: 进程是cpu资源分配的最小单元. 线程是cpu计算的最小单元. 第二: 一个进程中可以有多个线程. ...
- 《Python》进程收尾线程初识
一.数据共享 from multiprocessing import Manager 把所有实现了数据共享的比较便捷的类都重新又封装了一遍,并且在原有的multiprocessing基础上增加了新的机 ...
- python之进程和线程的对比
python之进程和线程的对比 1. 进程和线程的对比的三个方向 关系对比 区别对比 优缺点对比 2. 关系对比 线程是依附在进程里面的,没有进程就没有线程. 一个进程默认提供一条线程,进程可以创建多 ...
- python 多线程和协程结合_一文讲透 “进程、线程、协程”
本文从操作系统原理出发结合代码实践讲解了以下内容: 什么是进程,线程和协程? 它们之间的关系是什么? 为什么说Python中的多线程是伪多线程? 不同的应用场景该如何选择技术方案? ... 什么是进程 ...
- Linux进程与线程的区别
2019独角兽企业重金招聘Python工程师标准>>> Linux进程与线程的区别 cnyinlinux 本文较长,耐心阅读,必有收获! 进程与线程的区别,早已经成为了经典问题.自线 ...
- python提高——进程、线程、协程对比及代码实现
目录 1多任务 1.1并发 1.2并行 2线程 2.1引入线程 2.2线程进行顺序 2.3线程封装 2.4多线程-共享全局变量 2.5资源竞争 2.6互斥锁 2.7死锁 3进程 3.1进程创建 3.2 ...
最新文章
- 设计模式之美:Memento(备忘录)
- 第二节 线程启动、结束、创建线程多个方法、join()、detach()
- 又拍云再放大招,CDN同时支持HTTP/2和SPDY/3.1协议
- C++中explicit关键字的作用
- 开发日记-20190504 关键词 汇编语言(三)
- bzoj千题计划128:bzoj4552: [Tjoi2016Heoi2016]排序
- 获取Class对象的三种方式
- 关于java几种输出的区别
- 改变libreOffice的Calc的背景颜色
- 余弦欧式距离matlab,余弦相似度和欧几里得距离
- Elastic全球用户大会Elastic{ON}首次落地北京
- mysql集群负载均衡,这些知识你必须拿下
- HDU 5025 Saving Tang Monk【bfs搜索】【北大ACM/ICPC竞赛训练】
- java解析魔兽争霸3录像_GitHub - wucao/jw3gparser: Java Warcraft Ⅲ Replay Parser(Java解析《魔兽争霸3》游戏录像工具)...
- 笔记本无法打开摄像头
- Oracle EBS使用CSV导入Oracle Form及BOM清单导入 API
- 从零开始学Vue3——(一)入门
- 数据挖掘的过程有哪些
- linux安装python3
- 去除spire.doc去水印
热门文章
- drbd+corosync+pacemaker实现mysql的高可用性“上”
- WSUS 3.0 SP2 部署安装
- 27. 安全 HTTP (2)
- 56. magento 判断 https or http
- 1. SOAP 简介
- 7. XSD 简易元素
- 48. PHP 页面静态化(1)
- 计生专干招聘计算机,请求解决招聘计生专干待遇
- Selenium 与 Android自动化测试
- Windows系统CVE整理