Python 多线程与多进程

PythonPythonBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

踏入一个工业革命重塑社会的世界,19世纪维多利亚时代的喧嚣生活塑造了鹅卵石街道。在这里,在雾气弥漫的小巷中,回荡着马车的辘辘声和远处工厂机器的嗡嗡声,住着一个以其才华吸引众多人群的人物——一位以令人难以置信的多任务处理能力而闻名的街头艺人。

我们的艺人名叫奥利弗,他以在独轮车上保持平衡的同时 juggling 物体、吹奏口琴并同时解复杂谜题而闻名。令观众惊叹的是,奥利弗的表演流畅而高效,这证明了他对并发活动的掌控能力。本实验旨在通过深入研究Python的多线程和多进程能力来模仿奥利弗的多任务处理能力,确保程序员能够顺利地同时管理多个任务。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("Python")) -.-> python/AdvancedTopicsGroup(["Advanced Topics"]) python/AdvancedTopicsGroup -.-> python/threading_multiprocessing("Multithreading and Multiprocessing") subgraph Lab Skills python/threading_multiprocessing -.-> lab-271599{{"Python 多线程与多进程"}} end

理解线程

在这一步中,你将学习Python中线程的基础知识。线程允许你并发地运行多个操作,让你的程序看起来好像同时在做不止一件事,就像奥利弗在骑车时 juggle 的能力一样。

~/project 目录下打开一个名为 simple_threads.py 的文件,其内容如下:

import threading
import time

def print_numbers():
    for i in range(1, 6):
        time.sleep(1)
        print(i)

## 创建两个线程
thread1 = threading.Thread(target=print_numbers)
thread2 = threading.Thread(target=print_numbers)

## 启动两个线程
thread1.start()
thread2.start()

## 等待两个线程完成
thread1.join()
thread2.join()

print("完成数字打印!")

在终端中使用以下命令运行上述代码:

python simple_threads.py

你应该会看到两个线程交错打印数字,然后是 “完成数字打印!”:

1
1
2
2
3
3
4
4
5
5
完成数字打印!

利用多进程

现在,让我们使用多进程来加速计算。Python 中的多进程允许执行多个进程,这些进程可以在不同的 CPU 核心上运行,从而减少 CPU 密集型任务所需的总时间。

~/project 目录下打开一个名为 process_prime.py 的文件,其内容如下:

from multiprocessing import Process
import math

def is_prime(num):
    """
    检查一个数是否为质数。
    """
    if num <= 1:
        return False
    for i in range(2, int(math.sqrt(num)) + 1):
        if num % i == 0:
            return False
    return True

def compute_primes(start, end):
    """
    计算给定范围内的质数。
    """
    prime_numbers = [num for num in range(start, end) if is_prime(num)]
    print(f"范围 {start}-{end} 内的质数: {prime_numbers}")

processes = []
## 创建两个进程
for i in range(0, 20000, 10000):
    ## 创建一个新进程,目标是 compute_primes 函数,并将范围作为参数传递
    p = Process(target=compute_primes, args=(i, i+10000))
    processes.append(p)
    ## 启动进程
    p.start()

## 等待所有进程完成
for p in processes:
    p.join()

print("质数计算完成!")

在终端中执行该脚本:

python process_prime.py

这将输出在指定范围内找到的质数,并显示完成消息:

范围 0-10000 内的质数: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241,
......
9851, 9857, 9859, 9871, 9883, 9887, 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973]
范围 10000-20000 内的质数: [10007, 10009, 10037, 10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, 10133, 10139, 10141, 10151, 10159, 10163, 10169, 10177, 10181, 10193,
......
19739, 19751, 19753, 19759, 19763, 19777, 19793, 19801, 19813, 19819, 19841, 19843, 19853, 19861, 19867, 19889, 19891, 19913, 19919, 19927, 19937, 19949, 19961, 19963, 19973, 19979, 19991, 19993, 19997]
质数计算完成!

总结

在本实验中,我们踏上了一段引人入胜的旅程,去剖析Python中线程和多进程的细微差别,这类似于维多利亚时代街头艺人的多层表演。我们首先用线程来 juggle 任务,然后升级到跨CPU核心处理繁重的操作。这个练习不仅展示了Python的并行能力,还揭示了这些技术如何具有类似于我们的角色奥利弗所展示的多方面技能的现实世界意义。

你从本实验中应该获得的收获包括对用于I/O密集型任务的Python线程以及用于CPU密集型任务的进程有清晰的理解,从而有效地提升你的编码性能并使你的应用程序更高效。