栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Python多线程详解

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Python多线程详解

Python多线程详解
  • 1 前言
    • 1.1 并发与并行
    • 1.2 进程、线程、协程
  • 2 线程介绍
    • 2.1 什么是线程
    • 2.2 为什么使用多线程
    • 2.3 进程与线程之间的区别
  • 3 线程实现
    • 3.1 普通创建方式
    • 3.2 自定义线程类
    • 3.3 守护线程
    • 3.4 主线程等待子线程结束
  • 4 GIL(Global Interpreter Lock)全局解释器锁
  • 参考

1 前言

本系列打算将 Python 中的线程、进程以及协程做一个全面的总结,本文目前是第一部分——多线程。在正式进入线程的讲解之前,我们先来熟悉一下相关的概念。

1.1 并发与并行
  • 并发:在操作系统中,某一时间段,几个程序在同一个CPU上运行,但在任意一个时间点上,只有一个程序在CPU上运行。
  • 并行:当操作系统有多个CPU时,一个CPU处理A线程,另一个CPU处理B线程,两个线程互相不抢占CPU资源,可以同时进行,这种方式成为并行。

即使在单核CPU上,如果运行速度较快,即使程序是在并发的交替执行,但是给我们带来的感受却像是在并行运行一样

1.2 进程、线程、协程
  • 进程:进程是执行中的程序(QQ在没有运行的情况下是应用程序,不是进程,只有我们双击运行它的时候,它才是进程),是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
  • 线程:线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位,也被称为轻量级进程。
  • 协程:

2 线程介绍 2.1 什么是线程

线程:线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位,也被称为轻量级进程。

2.2 为什么使用多线程

已经有了进程,为什么还需要线程?为了回答这个问题,我们需要再回顾一下进程的定义:进程是系统进行资源分配和调度的基本单位。系统为每个进程都分配了资源,使得进程之间不受资源的干扰,提高了计算机的运行效率。但是进程还是有缺陷的,主要有以下两点:

  1. 进程只能在一个时间干一件事,如果想同时干两件事或多件事,进程就无能为力了。
  2. 进程在执行的过程中如果阻塞,整个进程就会挂起。

相比之下,多线程编程具有以下优点:

  1. 同个进程下的线程共享内存,所以同进程下的多线程之间通信方便;
  2. 同个进程下的不同线程之间可以代价更小的切换,从而实现并发执行;
2.3 进程与线程之间的区别
  • 进程是CPU资源分配的基本单位,线程是独立运行和独立调度的基本单位(CPU上真正运行的是线程)。
  • 进程拥有自己的资源空间,一个进程包含若干个线程,线程与CPU资源分配无关,多个线程共享同一进程内的资源。
  • 线程的调度与切换比进程快很多。
  • 多进程对于多CPU,多线程对应多核CPU。

3 线程实现 3.1 普通创建方式
import threading
import time


def run(n):
    print("task", n)
    time.sleep(1)
    print(n + '-2s')
    time.sleep(1)
    print(n + '-1s')
    time.sleep(1)
    print(n + '-0s')
    time.sleep(1)


if __name__ == '__main__':
    t1 = threading.Thread(target=run, args=("t1",))  # 注意("t1",)是元组,一定要加逗号
    t2 = threading.Thread(target=run, args=("t2",))
    t1.start()
    t2.start()

运行结果如下:

task t1
task t2
t1-2s
t2-2s
t1-1s
t2-1s
t1-0s
t2-0s
3.2 自定义线程类
import threading
import time


class MyThread(threading.Thread):
    def __init__(self, n):
        super(MyThread, self).__init__()  # 重构run函数必须写
        self.n = n

    def run(self):
        print("task", self.n)
        time.sleep(1)
        print(self.n + '-2s')
        time.sleep(1)
        print(self.n + '-1s')
        time.sleep(1)
        print(self.n + '-0s')
        time.sleep(1)


if __name__ == '__main__':
    t1 = MyThread("t1")
    t2 = MyThread("t2")
    t1.start()
    t2.start()

运行结果如下:

task t1
task t2
t1-2s
t2-2s
t1-1s
t2-1s
t1-0s
t2-0s
3.3 守护线程

当其它非守护线程结束时,程序退出
在下面的代码中,我们使用 setDaemon(True) 将子线程设置为守护线程,所以当主线程结束时,子线程也会随之结束,进而整个程序退出。

import threading
import time


def run(n):
    print("task" + n)
    time.sleep(1)
    print(n + '-2s')
    time.sleep(1)
    print(n + '-1s')
    time.sleep(1)
    print(n + '-0s')
    time.sleep(1)


if __name__ == '__main__':
    t1 = threading.Thread(target=run, args=("t1",))  # 注意("t1",)是元组,一定要加逗号
    t2 = threading.Thread(target=run, args=("t2",))
    t1.setDaemon(True)
    t2.setDaemon(True)
    t1.start()
    t2.start()
    print("Done")

代码运行结果:

taskt1
taskt2
Done
3.4 主线程等待子线程结束

为了让守护线程执行结束之后,主线程再结束,我们可以使用join方法,让主线程等待子线程执行。

import threading
import time


def run(n):
    print("task" + n)
    time.sleep(1)
    print(n + '-2s')
    time.sleep(1)
    print(n + '-1s')
    time.sleep(1)
    print(n + '-0s')
    time.sleep(1)


if __name__ == '__main__':
    t1 = threading.Thread(target=run, args=("t1",))  # 注意("t1",)是元组,一定要加逗号
    t2 = threading.Thread(target=run, args=("t2",))
    t1.setDaemon(True)
    t2.setDaemon(True)
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print("Done")

代码运行结果如下:

taskt1
taskt2
t1-2s
t2-2s
t1-1s
t2-1s
t2-0s
t1-0s
Done
4 GIL(Global Interpreter Lock)全局解释器锁 参考
  • python多线程详解
  • 图解Python 【第八篇】:网络编程-进程、线程和协程
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/488943.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号