多线程与多进程(二)

简介: 多线程与多进程

线程锁

线程锁可以将临界区内的代码锁住,在同一时刻下,只有获得锁的线程可以进入,至于究竟哪个线程可以获得这把锁,则是由操作系统调度,或者是两个线程之间进行竞争,谁能先接触到锁,谁就能获得这把锁。

f20dc0537db0078837829b694a5e8824_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

使用锁,来保证在检查tasks中是否有元素时,tasks不能被修改。将上面的pop函数改写一下

lock = threading.Lock()
def pop():
    global tasks
    while tasks:
        time.sleep(2)
        # 获得锁
        lock.acquire()
        if tasks:
            print(tasks.pop())
        else:
            break
        # 释放锁
        lock.release()

通过使用线程锁将检查tasks和tasks.pop()两个动作锁起来,确保只有一个线程可以运行这两行代码,从而保证检查结果和检查后的结果一致。使用线程锁是为了避免资源竞争,但是如果锁使用的不合适,会让你的多线程程序退化为单线程程序。

如果我们将上面的pop函数改为下面这种,使用锁将整段代码全部锁住,那么这段代码和直接使用一个for循环相比速度差别不大,甚至会变得更慢(存在线程调度)。

def pop():
    global tasks
    lock.acquire()
    while tasks:
        time.sleep(2)
        if tasks:
            print(tasks.pop())
        else:
            break
    lock.release()

所以,线程锁使用一般在一些不是很耗时,但是会存在资源竞争的地方,程序中的一些耗时操作一般不放入临界区内。

87f1f2d6a1dc4cbba1ce94a7757dcbd7_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

进程

在python中多进程是没有GIL锁的,也就是说,多进程可以同时使用多个CPU核。说的形象一定就是,使用多线程,你的CPU使用率最多能到30%,而多进程可以达到90%以上。

ccb6e305266508fbcf51dc30c5a5d154_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

进程的创建

进程与线程的创建一致,只是不再是使用Thread而是使用Process,创建方法与线程一样,也可以通过三种方式进行创建,这里请读者自行实现。

import multiprocessing
# target即为进程内部要运行的函数
# args为函数所需要的参数,要以tuple类型传入
thread = multiprocessing.Process(target=compress, args=(picture_id, ))

进程的启动方式

与线程不同,进程的实现更依赖于操作系统,python中进程有三种启动方式

  • spawn(unix和windows系统都可以使用)
  • fork(只有unix系统可以使用)
  • forkserver(只有unix系统可以使用)

三种启动方式,其中fork的效率最高,spawn的效率最低。使用set_start_method方法可以设置特定的启动方法,注意,这个方法只能被调用一次,一般会放在if __name__ == '__main__':下面。这里分析spawnfork两种启动方式的差别。

spawn

spawn的启动方式是通过将一份代码使用python解释器运行多次,其中主进程的__name____main__,而通过主进程启动子进程的__name____mp_main__

from multiprocessing import (
    Process, 
    set_start_method
)
import os
print('Hello, world. __name__: %s' % __name__)
def func():
    print(os.getpid())
if __name__ == '__main__':
    set_start_method('spawn')
    p1 = Process(target=func)
    p2 = Process(target=func)
    p1.start()
    p2.start()
    p1.join()
    p2.join()

069f2542b5ce0e23c1adcd1089c5aa43_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

你会发现,hello,world被打印了三次,也印证了spawn方式是通过将同一份代码执行了三次。分别是主进程一次,和两个子进程各执行了一次。

fork

fork则是使用的系统调用,在调用fork的位置直接获得子进程和父进程

from multiprocessing import (
    Process, 
    set_start_method
)
import os
print('Hello, world. __name__: %s' % __name__)
def func():
    print(os.getpid())
if __name__ == '__main__':
    set_start_method('fork')
    p1 = Process(target=func)
    p2 = Process(target=func)
    p1.start()
    p2.start()
    p1.join()
    p2.join()

4721c6f7e7d14218985764c5ecf42e6e_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

fork方式只打印了一次hello,world,即在主进程启动的时候,在主进程创建子进程的时候,没有将整个代码重新运行一遍,而是只在创建时,直接获得了子进程。熟悉linux系统中fork的同学应该会比较熟悉这种方式。所以同样的一份代码,放到windows系统是可以运行,但是放到Linux系统或者是苹果的macos系统的上就不能运行了,原因就出在了进程的启动方式不同。在编写多进程代码时,这一点要格外注意。

相关文章
|
1月前
|
消息中间件 并行计算 安全
进程、线程、协程
【10月更文挑战第16天】进程、线程和协程是计算机程序执行的三种基本形式。进程是操作系统资源分配和调度的基本单位,具有独立的内存空间,稳定性高但资源消耗大。线程是进程内的执行单元,共享内存,轻量级且并发性好,但同步复杂。协程是用户态的轻量级调度单位,适用于高并发和IO密集型任务,资源消耗最小,但不支持多核并行。
43 1
|
10天前
|
并行计算 数据处理 调度
Python中的并发编程:探索多线程与多进程的奥秘####
本文深入探讨了Python中并发编程的两种主要方式——多线程与多进程,通过对比分析它们的工作原理、适用场景及性能差异,揭示了在不同应用需求下如何合理选择并发模型。文章首先简述了并发编程的基本概念,随后详细阐述了Python中多线程与多进程的实现机制,包括GIL(全局解释器锁)对多线程的影响以及多进程的独立内存空间特性。最后,通过实例演示了如何在Python项目中有效利用多线程和多进程提升程序性能。 ####
|
15天前
|
Linux 调度 C语言
深入理解操作系统:进程和线程的管理
【10月更文挑战第32天】本文旨在通过浅显易懂的语言和实际代码示例,带领读者探索操作系统中进程与线程的奥秘。我们将从基础知识出发,逐步深入到它们在操作系统中的实现和管理机制,最终通过实践加深对这一核心概念的理解。无论你是编程新手还是希望复习相关知识的资深开发者,这篇文章都将为你提供有价值的见解。
|
12天前
|
Java
java小知识—进程和线程
进程 进程是程序的一次执行过程,是系统运行的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如CPU时间,内存空间,文件,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。 线程 线程,与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间做切换工作时,负担要比
23 1
|
17天前
深入理解操作系统:进程与线程的管理
【10月更文挑战第30天】操作系统是计算机系统的核心,它负责管理计算机硬件资源,为应用程序提供基础服务。本文将深入探讨操作系统中进程和线程的概念、区别以及它们在资源管理中的作用。通过本文的学习,读者将能够更好地理解操作系统的工作原理,并掌握进程和线程的管理技巧。
34 2
|
18天前
|
调度 Python
深入浅出操作系统:进程与线程的奥秘
【10月更文挑战第28天】在数字世界的幕后,操作系统悄无声息地扮演着关键角色。本文将拨开迷雾,深入探讨操作系统中的两个基本概念——进程和线程。我们将通过生动的比喻和直观的解释,揭示它们之间的差异与联系,并展示如何在实际应用中灵活运用这些知识。准备好了吗?让我们开始这段揭秘之旅!
|
1月前
|
存储 消息中间件 人工智能
进程,线程,协程 - 你了解多少?
本故事采用简洁明了的对话方式,尽洪荒之力让你在轻松无负担的氛围中,稍微深入地理解进程、线程和协程的相关原理知识
41 2
进程,线程,协程 - 你了解多少?
|
29天前
|
Python
Python中的多线程与多进程
本文将探讨Python中多线程和多进程的基本概念、使用场景以及实现方式。通过对比分析,我们将了解何时使用多线程或多进程更为合适,并提供一些实用的代码示例来帮助读者更好地理解这两种并发编程技术。
|
1月前
|
消息中间件 并行计算 安全
进程、线程、协程
【10月更文挑战第15天】进程、线程和协程是操作系统中三种不同的执行单元。进程是资源分配和调度的基本单位,每个进程有独立的内存空间;线程是进程内的执行路径,共享进程资源,切换成本较低;协程则更轻量,由用户态调度,适合处理高并发和IO密集型任务。进程提供高隔离性和安全性,线程支持高并发,协程则在资源消耗和调度灵活性方面表现优异。
45 2
|
1月前
|
算法 安全 调度
深入理解操作系统:进程与线程的管理
【10月更文挑战第9天】在数字世界的心脏跳动着的,不是别的,正是操作系统。它如同一位无形的指挥家,协调着硬件与软件的和谐合作。本文将揭开操作系统中进程与线程管理的神秘面纱,通过浅显易懂的语言和生动的比喻,带你走进这一复杂而又精妙的世界。我们将从进程的诞生讲起,探索线程的微妙关系,直至深入内核,理解调度算法的智慧。让我们一起跟随代码的脚步,解锁操作系统的更多秘密。
37 1

热门文章

最新文章

相关实验场景

更多
下一篇
无影云桌面