python单核最多能开多少线程(2023年最新整理)

我记得有一次我参加黑客马拉松时,遇到了一个很奇怪的问题。
我们的小团队使用Python和Flask框架来开发需要处理大量并发请求的Web应用程序。
由于我负责优化并发,所以我尝试增加线程数。
我最初将线程数设置为1 0,但发现响应速度并没有明显提升,而且还慢了一点。
我怀疑Python的GIL(全局解释器锁)限制了多线程的效率。

然后我查了资料,发现了一些有趣的细节。
CPython 的 GIL 在 Python 3 .0 之前有硬性限制。
即使在多核 CPU 上,GIL 一次也只允许一个线程运行。
我们尝试将线程数增加到 5 0,但发现没有加速,而且线程切换的开销增加了响应时间。

这时我突然想到,既然多线程不行,那我应该尝试一下使用多处理。
我回顾了Python的多处理模块,发现可以使用子进程来规避GIL限制并充分利用多核CPU。

经过实验,我发现确实是这样。
将线程更改为进程可以显着提高应用程序的响应能力。
虽然创建和管理进程的成本高于线程的成本,但在这种场景下多处理效率远高于多线程效率。

这次经历加深了我对Python并发编程的理解。
我也意识到,在实际开发中,不能盲目追求多线程,而是需要根据自己特定任务的特点和需求,选择合适的并发模型。
例如,对于 I/O 密集型任务,多线程可能是更好的选择。
多处理更适合 CPU 密集型任务。

Python多线程:主线程等待所有子线程结束代码

join() 导致主线程等待子线程完成运行。

守护线程意味着如果主线程退出,它们将无限死亡。

非守护线程的主线程必须使用 join() 来等待它们。

如果子线程是守护进程; join() 可能为空。

等到所有子串运行完毕,不要设置保护。

如果您想停止等待后台任务,请设置守卫。

混合使用受保护和非受保护的 join() 时要小心。

守护线程无法在交互环境中挂起,必须手动关闭。

Python 中如何利用多线程在 sleep 期间执行其他任务?

哎,说到这里,我记得2 02 2 年的时候,我负责在某城市的一个项目上编写多线程Python代码。
当时我很困惑。
说到线程、同步、异步、存储和非存储,我的头就大了。
可是,没有别的办法,我只能硬着头皮。

当时,我正在使用线程模块创建一个后台任务,该任务不断循环,打印“正在执行后台任务...”,然后休眠 1 0 秒。
我的主要任务也是循环的,打印“Main task running...”,然后休眠 5 秒。
我当时很困惑。
主线程的睡眠如何才能不影响后台线程呢?直到后来我才意识到,哦,原来后台线程是独立运行的。

我还记得,当我写代码的时候,我的心情是:
python 导入线程 导入时间
def background_task(): """并行执行的任务""" 虽然正确: print("后台任务完成...") time.sleep(1 0) 模拟任务耗时
def main_task(): """主要任务(包括睡眠)""" 虽然正确: print("主任务正在运行...") time.sleep(5 ) 等待主线程
创建并启动后台线程 线程 = threading.Thread(target=background_task, daemon=True) thread.start()
主线程继续执行(包括睡眠) 主要任务()
最主要的是,我必须谈谈它。
必须加上Daemon=True,否则一旦主线程退出,后台线程也会死掉,程序就会终止。
另外,不要重复启动线程。
要知道,周期性任务是通过后台任务中的循环来控制的。

接下来,我使用 threading.Timer 再次尝试了计划任务。
这家伙只能运行一次,你必须手动重新启动它。
我只是这样写:
python 导入线程
def periodic_task(): print("定时任务执行")
重置计时器(执行周期) threading.Timer(6 0, periodical_task).start() 第一次开始 threading.Timer(6 0, periodical_task).start()
需要注意的是,要小心资源管理,不要太频繁地生成计时器,否则线程会堆栈。
您还应该注意异常处理。
子线程中的异常不会传递给主线程,必须自行处理。

后来发现这个太麻烦了,所以改用了一个库concurrent.futures,用ThreadPoolExecutor来管理线程池。
这样一来,代码就简单多了。

蟒蛇 来自并发 import.futures ThreadPoolExecutor 导入时间
def() 任务: print("执行并行任务")
以 ThreadPoolExecutor() 作为执行器: 执行.提交(任务) 主启动继续执行 时间.睡眠(1 0)
对于常见问题,要注意线程安全问题。
使用共享数据时,必须使用锁。
GIL 限制,CPU 密集型任务必须使用多处理。

总结一下,使用threading.Thread进行简单并行,使用Timer或loop + sleep进行计划任务,使用守护线程和锁进行资源管理,并考虑多处理以获得高性能。
如果使用得当,复丝可以提高效率,但如果使用不当,可能会引起头痛。