多线程和多进程
先来了解一下多线程和多进程
多线程:
- 多线程指的是在一个进程内创建多个线程并行执行。所有线程共享进程的地址空间,因此它们可以访问相同的变量和资源。
- 多线程的创建和切换开销较小,可以更高效地利用计算机的内存和CPU资源。
- 由于Python解释器的全局解释器锁(GIL),多线程的执行并不能充分利用多核处理器的优势,所以多线程更适用于IO密集型的任务。
- 在多线程编程中,需要注意线程安全的问题,避免多个线程同时访问和修改共享资源导致的竞态条件和数据不一致问题。
多进程:
- 多进程指的是在操作系统中创建多个独立的进程并行执行。每个进程有自己独立的地址空间,互相之间不共享变量和资源。
- 多进程的创建和切换开销较大,每个进程都需要独立的资源分配,所以相比多线程,多进程的开销更高。
- 多进程可以充分利用多核处理器的优势,适用于计算密集型的任务。
- 多进程之间的通信相对复杂,可以使用IPC(进程间通信)机制,如管道、套接字、共享内存等。
***其中进程属于资源单位,一个进程中至少要包含一个线程
- 多线程
# 引入多线程类
from threading import Thread
def task():
for i in range(10):
print("副线程 ",i)
threads = []
if __name__ == '__main__':
# 创建多个线程
# for i in range(3):
# t = Thread(target=task)
# threads.append(t)
#
# for t in threads:
# t.start()
# 创建单个线程
t = Thread(target=task) # 创建线程,并发给他 task() 这个任务
t.start() # 给予线程可执行的状态
for k in range(10):
print("主线程 ",k)
"""
运行结果:出现了主线程和副线程在一起的情况,表明在这一时刻,两个线程同时执行了
副线程 0
副线程 1
副线程 2
副线程 3
副线程 主线程 0
主线程 4
副线程 1
5
副线程 6
副线程 7主线程 2
主线程
副线程 8 3
副线程 主线程 9
4
主线程 5
主线程 6
主线程 7
主线程 8
主线程 9
"""
- 多进程 (多进程和多线程的写法是基本一样的)
# 引入多进程类
from multiprocessing import Process
def task():
for i in range(100000):
print("副进程 ",i)
if __name__ == '__main__':
# 创建单个线程
t = Process(target=task) # 创建线程,并发给他 task() 这个任务
t.start() # 给予线程可执行的状态
for i in range(100000):
print("主进程 ",i)
- 进程池和线程池(开辟一定量的线程/进程,给他们发任务,由池子决定哪个线程/进程什么时候干什么,干多少)
线程池: 线程池是一组已经创建并随时待命的线程,可以用于执行任务。线程池可以避免频繁地创建和销毁线程,减少了系统开销,并能够更好地利用系统资源。当有新任务提交给线程池时,线程池会从池中选择一个线程来执行任务,当任务执行完毕后,线程会返回到线程池,以便重用。
from concurrent.futures import ThreadPoolExecutor
def task():
# 任务执行的操作
if __name__ == '__main__':
# 创建线程池,指定线程数量
executor = ThreadPoolExecutor(max_workers=5)
# 提交任务给线程池
future = executor.submit(task)
# 获取任务的结果
result = future.result()
进程池: 进程池是一组已经创建并随时待命的进程,可以用于执行任务。进程池与线程池类似,可以避免频繁地创建和销毁进程,减少了系统开销,并能够更好地利用系统资源。当有新任务提交给进程池时,进程池会从池中选择一个进程来执行任务,当任务执行完毕后,进程会返回到进程池,以便重用。
from concurrent.futures import ProcessPoolExecutor
def task():
# 任务执行的操作
if __name__ == '__main__':
# 创建进程池,指定进程数量
executor = ProcessPoolExecutor(max_workers=5)
# 提交任务给进程池
future = executor.submit(task)
# 获取任务的结果
result = future.result()
from concurrent.futures import ThreadPoolExecutor
def ii(name):
for i in range(100000):
print(f'线程{name}',i)
if __name__ == '__main__':
# 开辟线程池,with可以自动关闭
with ThreadPoolExecutor(50) as t:
for i in range(10): # 任务数
t.submit(ii,i)
# 第二种
def ii():
for i in range(1000):
print( i)
if __name__ == '__main__':
executor = ThreadPoolExecutor(max_workers=10)
executor.submit(ii) # 可以直接提交一个集合
协程
协程(Coroutine)是一种基于生成器(Generator)的异步编程模型,它可以在单线程中实现并发执行的效果。在 Python 中,协程的实现主要依赖于 asyncio
模块。协程的意义在于可以在一个函数中暂停执行,切换到另一个协程执行,待到某个条件满足后再切换回原来的协程,从而实现非阻塞的并发操作。
简单的解释就是,我煮饭需要40分钟(阻塞状态,在单个线程中处于阻塞状态时,该线程停止。如input函数,只有输入之后线程才继续,协程就是在等待过程中让该线程去做其他事),但其中的30分钟是电饭煲自动工作的,在这30分钟内我就可以去干别的事情,等做好了我再来。即多任务异步操作(仅单线程下)。
# 注意当出现同步操作时,异步操作就会停止
import asyncio
# 协程函数
async def task1():
print("Task 1: Start")
await asyncio.sleep(2) # 将其改为异步操作
print("Task 1: Complete")
async def task2():
print("Task 2: Start")
await asyncio.sleep(3)
print("Task 2: Complete")
async def task3():
print("Task 3: Start")
await asyncio.sleep(1)
print("Task 3: Complete")
async def ma():
# 创建任务表
tasks = [
asyncio.create_task(task1()),
asyncio.create_task(task2()),
asyncio.create_task(task3())
]
await asyncio.wait(tasks)
if __name__ == '__main__':
# 执行任务
asyncio.run(ma())
- 将其写到爬虫中
先下载aiohttp(pip install aiohttp)
import asyncio
import aiohttp
# 爬取页面的异步任务
async def fetch(session, url):
async with session.get(url) as response:
return await response.text()
# 主函数
async def main():
# 创建一个Session对象 其中的with是当运行结束时自动关闭该资源
async with aiohttp.ClientSession() as session:
# 定义要爬取的页面列表
urls = ['http://example.com/page1', 'http://example.com/page2', 'http://example.com/page3']
# 创建任务列表
tasks = [
asyncio.create_task(fetch(session, url)) for url in urls
]
# 等待所有任务完成
responses = await asyncio.gather(*tasks)
# 处理响应结果
for response in responses:
print(response)
if __name__ == '__main__':
# 运行主函数
asyncio.run(main())
Selenium
Selenium简单的理解就是像人一样去浏览网站,我们能做的,他也可以。还是一样先安装库(pip install selenium),然后下载相应浏览器的驱动(如没有对应版本选前一个版本即可)
# 引入库和驱动,我用的时谷歌
from selenium.webdriver import Chrome
# 创建浏览浏览器
web = Chrome()
# 通过程序自动打开网站
web.get("http://www.baidu.com/")
s = input() # 让其停止以便看到结果
自动打开成功
- Selenium是一个在爬虫中比较重要的内容,这里仅作引子。如果要讲清楚它,我应该都可以出书了。那么对于这里的内容,等到例子里遇到了再说吧