前言
此篇文章将深入的讲解Python中的多进程和多线程
📝个人主页→数据挖掘博主ZTLJQ的主页
个人推荐python学习系列:
☄️爬虫JS逆向系列专栏 - 爬虫逆向教学
☄️python系列专栏 - 从零开始学python
第一部分:多进程
多进程是指在操作系统中同时运行多个独立的程序或子进程。Python中的multiprocessing模块提供了创建和管理多进程的功能。
案例1:使用多进程进行计算密集型任务
import multiprocessing
def square(n):
return n*n
if __name__ == '__main__':
numbers = [1, 2, 3, 4, 5]
pool = multiprocessing.Pool()
results = pool.map(square, numbers)
pool.close()
pool.join()
print(results)
解释:
- 定义了一个square函数,用于计算给定数值的平方。
- 在主程序中,创建了一个数字列表numbers。
- 使用multiprocessing.Pool()创建一个进程池pool。
- 调用pool.map()方法,将square函数应用到numbers列表中的每个数值上进行计算。
- 最后,输出计算结果。
案例2:使用多进程进行IO密集型任务
import multiprocessing
import requests
def download(url):
response = requests.get(url)
content = response.content
with open('file_' + url.split('/')[-1], 'wb') as file:
file.write(content)
if __name__ == '__main__':
urls = ['http://example.com', 'http://example.org', 'http://example.net']
pool = multiprocessing.Pool()
pool.map(download, urls)
pool.close()
pool.join()
解释:
- 导入requests模块,用于发送HTTP请求。
- 定义了一个download函数,用于下载给定URL的内容,并保存为文件。
- 在主程序中,创建了一个URL列表urls。
- 使用multiprocessing.Pool()创建一个进程池pool。
- 调用pool.map()方法,将download函数应用到urls列表中的每个URL上进行下载。
- 最后,所有文件下载完成后,进程池关闭。
案例3:多进程实现并行任务
import multiprocessing
import time
def task(name):
print(f'Starting task {name}')
time.sleep(2)
print(f'Finished task {name}')
if __name__ == '__main__':
processes = []
for i in range(1, 6):
p = multiprocessing.Process(target=task, args=(f'Task {i}',))
p.start()
processes.append(p)
for p in processes:
p.join()
print('All tasks completed.')
解释:
- 定义了一个task函数,模拟一个耗时的任务,并在开始和结束时打印相关信息。
- 在主程序中,创建了一个进程列表processes。
- 使用for循环创建并启动5个子进程,每个子进程执行task函数,并传入不同的任务名称作为参数。
- 调用join()方法等待所有子进程的执行完成。
- 最后,打印所有任务完成的提示信息。
第二部分:多线程
多线程是指在一个程序中同时运行多个独立的线程。Python中的threading模块提供了创建和管理多线程的功能。
案例1:使用多线程进行并发请求
import threading
import requests
def fetch(url):
response = requests.get(url)
content = response.content
print(f'Response from {url}: {content}')
if __name__ == '__main__':
urls = ['http://example.com', 'http://example.org', 'http://example.net']
threads = []
for url in urls:
t = threading.Thread(target=fetch, args=(url,))
threads.append(t)
t.start()
for t in threads:
t.join()
解释:
- 导入requests模块,用于发送HTTP请求。
- 定义了一个fetch函数,用于请求给定URL的内容,并输出响应内容。
- 在主程序中,创建了一个URL列表urls。
- 创建一个线程列表threads来存储所有的子线程。
- 使用for循环创建子线程,每个子线程都调用fetch函数,并传入不同的URL参数。
- 调用start()方法启动子线程,使它们开始执行。
- 最后,使用join()方法等待所有子线程的执行完成,并输出响应结果。
案例2:多线程实现资源共享
import threading
count = 0
lock = threading.Lock()
def increment():
global count
with lock:
count += 1
print(f'Count: {count}')
if __name__ == '__main__':
threads = []
for i in range(10):
t = threading.Thread(target=increment)
t.start()
threads.append(t)
for t in threads:
t.join()
print('Final count:', count)
解释:
- 定义了一个全局变量count,用于记录递增的值。
- 创建了一个线程锁lock,用于保护共享资源count的访问。
- 定义了一个increment函数,使用线程锁来确保每次递增操作的原子性。
- 在主程序中,创建了一个线程列表threads。
- 使用for循环创建并启动10个子线程,每个子线程执行increment函数。
- 调用join()方法等待所有子线程的执行完成。
- 最后,打印最终的count值。
案例3:多线程队列示例
import threading
import queue
def producer(q, name):
for i in range(5):
message = f'Message {i} from {name}'
q.put(message)
print(f'Produced: {message}')
def consumer(q, name):
while not q.empty():
message = q.get()
print(f'Consumed by {name}: {message}')
if __name__ == '__main__':
q = queue.Queue()
p1 = threading.Thread(target=producer, args=(q, 'Producer 1'))
p2 = threading.Thread(target=producer, args=(q, 'Producer 2'))
c1 = threading.Thread(target=consumer, args=(q, 'Consumer 1'))
c2 = threading.Thread(target=consumer, args=(q, 'Consumer 2'))
p1.start()
p2.start()
c1.start()
c2.start()
p1.join()
p2.join()
c1.join()
c2.join()
print('All messages consumed.')
多线程队列示例是一个典型的生产者-消费者模型,其中有两个生产者线程(Producer 1和Producer 2)和两个消费者线程(Consumer 1和Consumer 2)。它们共享一个线程安全的队列(Queue)来进行信息交换。
在生产者线程中,每个生产者会循环生成5条消息,并将它们放入队列中。每条消息都包含了消息的编号和产生消息的生产者的名称。生产者线程在生产完所有消息之后结束。
在消费者线程中,每个消费者会不断地从队列中取出消息,并打印出消费的消息以及消费者的名称。消费者线程会一直运行,直到队列为空时才结束。
主线程创建并启动了所有生产者和消费者线程,并等待它们全部执行完毕。最后,主线程打印出"All messages consumed."表示所有消息都被消费完毕。
通过使用线程安全的队列,多线程之间可以安全地进行信息的传递和共享,避免了数据竞争和死锁等多线程编程常见问题。