在python中单线程,多线程,多进程对CPU的利用率实测以及GIL原理分析

简介: 首先关于在python中单线程,多线程,多进程对cpu的利用率实测如下: 单线程,多线程,多进程测试代码使用死循环。 1)单线程: 2)多线程: 3)多进程: 查看cpu使用效率: 开始观察分别执行时候cpu的使用效率:1)单线程执行的时候: 2)多线程执行的时候: 3)多进程执行的时候: 总结:1)单进程单线程时,对于双核CPU的利用率只能利用一个核,没有充分利用两个核。

首先关于在python中单线程,多线程,多进程对cpu的利用率实测如下:

 

单线程,多线程,多进程测试代码使用死循环。

 

1)单线程:

 

2)多线程:

 

3)多进程:

 

查看cpu使用效率:

 

开始观察分别执行时候cpu的使用效率:

1)单线程执行的时候:

 

2)多线程执行的时候:

 

3)多进程执行的时候:

 

总结:

1)单进程单线程时,对于双核CPU的利用率只能利用一个核,没有充分利用两个核。

2)单进程多线程时,对于双核CPU的来说,虽然两个核都用到的,不过很明显没有充分利用两个核,这里要说一个GIL(全局解释器锁)的概念:

GIL不同于线程之间的互斥锁,GIL并不是Python的特性,而是Cpython引入的一个概念。(Jpython,PYPY)

Python的代码由Python的解释器执行(CPython)。那么我们的代码什么时候被python解释器执行,由我们的GIL也就是全局解释器锁进行控制。

当我们有一个线程开始访问解释器的时候,GIL会将这把锁上锁,也就是说,其他线程无法再访问解释器,也就意味着,其他的线程无法再被执行。

 

GIL执行流程:

 

  1. 加锁GIL

  2. 切换到一个线程去执行。

  3. 运行。

  4. 解锁GIL

再次重复以上步骤。

对于下列代码GIL的执行流程:

 

import threading
import time
# 写两个函数,分别让两个线程去执行
# 这个两个函数,都要访问我的全局变量
number = 0

def test1(count):
    global number
    for i in range(count):
        number += 1
    print(number)

def test2(count):
    global number
    for i in range(count):
        number += 1
    print(number)


def main():
    th1 = threading.Thread(target=test1,args= (1000000,))
    th2 = threading.Thread(target=test2, args=(1000000,))
    th1.start()
    th2.start()

    time.sleep(5)
    print(number)

if __name__ == '__main__':
    main()

 

运行结果(这里充分的说明了多线程资源抢占问题):

流程图如下:

线程1在执行到对全局变量加一操作的时候全局解释器锁被收回,线程2申请并得到了全局解释器锁开始运行,在线程2执行完加一操作以后对全局变量进行了修改并释放了全局解释器锁。

这时线程1再次得到了全局解释器锁,从上次释放全局解释器锁的地方开始继续执行对全局变量加一的操作,记住,这里线程1中的全局变量还是开始的0,虽然线程2已经对其进行了加一的操作,但是线程1并不知道,线程1还是会接着上一次的位置开始执行,所以线程1在执行完加一操作的时候同样把1再次赋值给了全局变量num,也就是说,线程2执行完加一操作之后赋值过去的1又被线程1赋值过去的1所覆盖,加了两次等于加了一次!类似于协程,只是做了一个执行代码来回切换的操作!

所以在Python中,同一时刻,只能有一个线程被执行。所以Python中的多线程是假的

既然这样我们为什么还要用多线程呢?

其实多线程也有它的好处,例如我们在进行IO操作的时候,有效的组织了程序的阻塞,不至于一直无限的等待。

3)多进程时,对于双核CPU来说,每个进程的优先级都是同等的,所分配的资源也是相等的,两个进程的时候完全可以充分的利用双核CPU,而且由于计算密集型的任务完全是依靠于cpu的核数,所以需要尽量的完全利用cpu,这时候多进程的好处就能够完美的体现出来。

 

 

                                                                   -------  知识无价,汗水有情,如需搬运请注明出处,谢谢!

目录
相关文章
|
9天前
|
安全 Java 数据处理
Python网络编程基础(Socket编程)多线程/多进程服务器编程
【4月更文挑战第11天】在网络编程中,随着客户端数量的增加,服务器的处理能力成为了一个重要的考量因素。为了处理多个客户端的并发请求,我们通常需要采用多线程或多进程的方式。在本章中,我们将探讨多线程/多进程服务器编程的概念,并通过一个多线程服务器的示例来演示其实现。
|
14天前
|
Java 调度
Java并发编程:深入理解线程池的原理与实践
【4月更文挑战第6天】本文将深入探讨Java并发编程中的重要概念——线程池。我们将从线程池的基本原理入手,逐步解析其工作过程,以及如何在实际开发中合理使用线程池以提高程序性能。同时,我们还将关注线程池的一些高级特性,如自定义线程工厂、拒绝策略等,以帮助读者更好地掌握线程池的使用技巧。
|
26天前
|
安全 Python
Python中的并发编程:多线程与多进程技术探究
本文将深入探讨Python中的并发编程技术,重点介绍多线程和多进程两种并发处理方式的原理、应用场景及优缺点,并结合实例分析如何在Python中实现并发编程,以提高程序的性能和效率。
|
2天前
|
调度 Python
Python多线程、多进程与协程面试题解析
【4月更文挑战第14天】Python并发编程涉及多线程、多进程和协程。面试中,对这些概念的理解和应用是评估候选人的重要标准。本文介绍了它们的基础知识、常见问题和应对策略。多线程在同一进程中并发执行,多进程通过进程间通信实现并发,协程则使用`asyncio`进行轻量级线程控制。面试常遇到的问题包括并发并行混淆、GIL影响多线程性能、进程间通信不当和协程异步IO理解不清。要掌握并发模型,需明确其适用场景,理解GIL、进程间通信和协程调度机制。
18 0
|
24天前
|
监控 Linux Shell
Linux 进程问题调查探秘:分析和排查频繁创建进程问题
Linux 进程问题调查探秘:分析和排查频繁创建进程问题
39 0
|
24天前
|
消息中间件 存储 网络协议
Linux IPC 进程间通讯方式的深入对比与分析和权衡
Linux IPC 进程间通讯方式的深入对比与分析和权衡
65 0
|
24天前
|
存储 监控 Linux
Linux 使用getrusage系统调用获取cpu信息:一个C++实例分析
Linux 使用getrusage系统调用获取cpu信息:一个C++实例分析
48 0
|
24天前
|
存储 算法 Linux
【Linux 系统标准 进程资源】Linux 创建一个最基本的进程所需的资源分析,以及线程资源与之的差异
【Linux 系统标准 进程资源】Linux 创建一个最基本的进程所需的资源分析,以及线程资源与之的差异
25 0
|
26天前
|
并行计算 Python
Python中的并发编程:多线程与多进程的比较
在Python编程中,实现并发操作是提升程序性能的重要手段之一。本文将探讨Python中的多线程与多进程两种并发编程方式的优劣及适用场景,帮助读者更好地选择合适的方法来提高程序运行效率。
|
29天前
|
消息中间件 存储 算法
【C/C++ 泡沫精选面试题04】在实际项目中,多进程和多线程如何选择?
【C/C++ 泡沫精选面试题04】在实际项目中,多进程和多线程如何选择?
43 1