前言
此篇文章将深入的讲解Python中的多进程和多线程
📝个人主页→数据挖掘博主ZTLJQ的主页
个人推荐python学习系列:
☄️爬虫JS逆向系列专栏 - 爬虫逆向教学
☄️python系列专栏 - 从零开始学python
第一部分:多进程
多进程是指在操作系统中同时运行多个独立的程序或子进程。Python中的multiprocessing模块提供了创建和管理多进程的功能。
案例1:使用多进程进行计算密集型任务
import multiprocessingdef square(n):return n*nif __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 requestsdef download(url):response = requests.get(url)content = response.contentwith 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 timedef 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 requestsdef fetch(url):response = requests.get(url)content = response.contentprint(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 threadingcount = 0
lock = threading.Lock()def increment():global countwith lock:count += 1print(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 queuedef 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."表示所有消息都被消费完毕。
通过使用线程安全的队列,多线程之间可以安全地进行信息的传递和共享,避免了数据竞争和死锁等多线程编程常见问题。