La programmation simultanée fait référence à une conception de programme qui peut effectuer plusieurs opérations sur une période donnée. Elle se manifeste généralement par le fait que plusieurs tâches du programme sont démarrées en même temps et peuvent s'exécuter sans s'influencer mutuellement. L'avantage de la programmation simultanée est qu'elle peut améliorer les performances et la réactivité du programme.
Les programmes Crawler sont des tâches typiques gourmandes en E/S, le multithread et les E/S asynchrones sont tous deux de bons choix, car lorsque le programme atteint une certaine partie. du programme est bloqué à cause d'opérations d'E/S, d'autres parties du programme peuvent toujours s'exécuter, de sorte que nous n'avons pas à perdre beaucoup de temps à attendre et à bloquer.
Regardons d'abord la version monothread du programme d'exploration. Ce programme d'exploration utilise la bibliothèque requests
pour obtenir des données JSON et enregistre l'image localement via la fonction open
. requests
库获取 JSON 数据,并通过open
函数将图片保存到本地。
""" example04.py - 单线程版本爬虫 """ import os import requests def download_picture(url): filename = url[url.rfind('/') + 1:] resp = requests.get(url) if resp.status_code == 200: with open(f'images/beauty/{filename}', 'wb') as file: file.write(resp.content) def main(): if not os.path.exists('images/beauty'): os.makedirs('images/beauty') for page in range(3): resp = requests.get(f'<https://image.so.com/zjl?ch=beauty&sn=>{page * 30}') if resp.status_code == 200: pic_dict_list = resp.json()['list'] for pic_dict in pic_dict_list: download_picture(pic_dict['qhimg_url']) if __name__ == '__main__': main()
在 macOS 或 Linux 系统上,我们可以使用time
命令来了解上面代码的执行时间以及 CPU 的利用率,如下所示。
time python3 example04.py
下面是单线程爬虫代码在我的电脑上执行的结果。
python3 example04.py 2.36s user 0.39s system 12% cpu 21.578 total
这里我们只需要关注代码的总耗时为21.578
秒,CPU 利用率为12%
。
我们使用之前讲到过的线程池技术,将上面的代码修改为多线程版本。
""" example05.py - 多线程版本爬虫 """ import os from concurrent.futures import ThreadPoolExecutor import requests def download_picture(url): filename = url[url.rfind('/') + 1:] resp = requests.get(url) if resp.status_code == 200: with open(f'images/beauty/{filename}', 'wb') as file: file.write(resp.content) def main(): if not os.path.exists('images/beauty'): os.makedirs('images/beauty') with ThreadPoolExecutor(max_workers=16) as pool: for page in range(3): resp = requests.get(f'<https://image.so.com/zjl?ch=beauty&sn=>{page * 30}') if resp.status_code == 200: pic_dict_list = resp.json()['list'] for pic_dict in pic_dict_list: pool.submit(download_picture, pic_dict['qhimg_url']) if __name__ == '__main__': main()
执行如下所示的命令。
time python3 example05.py
代码的执行结果如下所示:
python3 example05.py 2.65s user 0.40s system 95% cpu 3.193 total
我们使用aiohttp
将上面的代码修改为异步 I/O 的版本。为了以异步 I/O 的方式实现网络资源的获取和写文件操作,我们首先得安装三方库aiohttp
和aiofile
""" example06.py - 异步I/O版本爬虫 """ import asyncio import json import os import aiofile import aiohttp async def download_picture(session, url): filename = url[url.rfind('/') + 1:] async with session.get(url, ssl=False) as resp: if resp.status == 200: data = await resp.read() async with aiofile.async_open(f'images/beauty/{filename}', 'wb') as file: await file.write(data) async def main(): if not os.path.exists('images/beauty'): os.makedirs('images/beauty') async with aiohttp.ClientSession() as session: tasks = [] for page in range(3): resp = await session.get(f'<https://image.so.com/zjl?ch=beauty&sn=>{page * 30}') if resp.status == 200: pic_dict_list = (await resp.json())['list'] for pic_dict in pic_dict_list: tasks.append(asyncio.ensure_future(download_picture(session, pic_dict['qhimg_url']))) await asyncio.gather(*tasks) if __name__ == '__main__': loop = asyncio.get_event_loop() loop.run_until_complete(main())
time
pour comprendre le temps d'exécution du code ci-dessus et l'utilisation du processeur, comme indiqué ci-dessous. time python3 example04.pyCe qui suit est le résultat du code du robot d'exploration monothread exécuté sur mon ordinateur.
python3 exemple04.py 2,36s utilisateur 0,39s système 12% cpu 21,578 totalIci, nous devons seulement faire attention au temps total pris par le code pour être de
21,578
secondes, et le L'utilisation du processeur est de 12 %
. Version multithreadExécutez la commande ci-dessous. 🎜time python3 example05.py🎜🎜🎜Le résultat de l'exécution du code est le suivant : 🎜🎜🎜python3 example05.py 2,65s utilisateur 0,40s système 95% cpu 3,193 total🎜🎜🎜Version E/S asynchrone 🎜🎜Nous useaiohttpModifiez le code ci-dessus vers la version d'E/S asynchrone. Afin de réaliser les opérations d'acquisition de ressources réseau et d'écriture de fichiers en E/S asynchrones, nous devons d'abord installer les bibliothèques tiercesNous utilisons la technologie de pool de threads mentionnée précédemment pour modifier le code ci-dessus en une version multithread.
rrreee
aiohttp
et aiofile
. 🎜🎜🎜pip install aiohttp aiofile🎜🎜🎜Ce qui suit est la version d'E/S asynchrone du code du robot. 🎜rrreee🎜Exécutez la commande ci-dessous. 🎜🎜🎜time python3 example06.py🎜🎜🎜Le résultat de l'exécution du code est le suivant : 🎜🎜🎜python3 example06.py 0,92s utilisateur 0,27s système 290% cpu 0,420 total🎜🎜🎜Par rapport à la version monothread de le programme d'exploration, plus Le temps d'exécution de la version threadée et de la version d'E/S asynchrones du programme d'exploration a été considérablement amélioré, et la version d'E/S asynchrones du programme d'exploration a été la plus performante. 🎜Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!