我的编程空间,编程开发者的网络收藏夹
学习永远不晚

python线程入门

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

python线程入门

目录

  • python线程入门
  • 线程与进程
    • 线程
    • 总结
    • 参考

python线程入门

正常情况下,我们在启动一个程序的时候。这个程序会先启动一个进程,启动之后这个进程会启动起来一个线程。这个线程再去处理事务。也就是说真正干活的是线程,进程这玩意只负责向系统要内存,要资源但是进程自己是不干活的。默认情况下只有一个进程只会拉起来一个线程。

多线程顾名思义,就是同样在一个进程的情况同时拉起来多个线程。真正干活的是线程。进程与线程的关系就像是工厂和工人的关系, 要想一个工厂运行起来,至少有一个工,当然如果工人多, 那么效率就变高了。因为只有一个进程,所以多线程在提高效率的同时,并没有向系统伸手要更多的内存资源。因此使用起来性价比还是很高的。但是虽然多线程不会消耗更多的内存,但是每个线程却需要CPU的的参与。

可以这样理解: 工厂虽然是固定的大小,可以容纳很多工人取干活, 但是工人干活儿需要人来协调, 如果工人太多, 对于一个固定的厂, CPU相当于厂长, 厂长的精力也是有限的, 当厂长(CPU忙不过不过来的时候效率也一样会有影响. 所以工人(线程)的数量最好还是在厂长(cpu)的能力(内核数)范围之内比较好。

线程与进程

  • 硬件发展:

    • cpu 切片,由之前的串行处理,到后来实行分片,同时执行一颗线程,处理效率更快.多核CPU 同一时刻可以执行多个线程。
  • 软件发展:

    1. 单进程单线程

    2. 多线程单进程的程序,

      • 同一个进程下的多个线程可能在多颗CPU上执行,一个线程不可能同时在多个cpu上。(其他语言会出现)
      • Python语言不会出现同一个进程下的多线程同时出现在多个CPU上,全局解释器锁GRL. 限定了当一个进程下的多个线程处理的时候,只能在一个CPU上执行,当一个线程被处理的时候,其他的线程只会等候;这样的缺点,处理效率很低。
    3. 多线程多进程的程序。

      进程的开销通常比线程昂贵,因为线程自动共享内存地址空间和文件描述符. 意味着, 创建进程比创建线程会花费更多的资源和时间

    4. 在执行一些sleep/read/write/recv/send这些会导致阻塞的函数时,当前线程会主动放弃GIL,然后调用相应的系统API,完成后再重新申请GIL。因此,GIL也并不是导致Python的多线程完全没用,在一些IO等待的场合,Python多线程还是发挥了作用,当然如果多线程都是用于CPU密集的代码,那多线程的执行效率就明显会比单线程的低。

  • 程序, 线程与 进程关系

    • 一个程序可能有多个多个进程, 某一个进程里面可以包含多个线程.

线程

创建线程

  • 如何实现: 使用threading 模块

  • 创建一个简单的线程

  • 启动一个线程就是把一个函数传入并创建Thread实例,然后调用start()开始执行

    启动一个线程

    #!/usr/bin/env python
    #-*-coding:utf-8-*-
    import time, threading
    
    
    # 线程执行的代码:
    def thread_demo():
        print('thread %s is running...' % threading.current_thread().name)
        n = 0
        while n < 5:
            n = n + 1
            print('thread %s >>> %s' % (threading.current_thread().name, n))
            time.sleep(1)
        print('thread %s ended.' % threading.current_thread().name)
    
    
    if __name__ == "__main__":
        print('thread %s is running...' % threading.current_thread().name)
        t = threading.Thread(target=thread_demo, name= "subThread")
        t.start()
        t.join()
        print('thread %s ended.' % threading.current_thread().name)
    • threading 模块可以直接用来创建一个线程.
    • t. start()用来启动线程
    • t.join 使多线程按顺序执行
    • threading.Thread实例化线程类.每实例化一个类,相当于开启一个线程, 参数target传递函数, name用来定义子线程的名字.

    启动多个线程

    #!/usr/bin/env python
    #-*-coding:utf-8-*-
    
    import threading
    import time
    
    def foo(num):
        for i in range(num):
            time.sleep(0.5)
            print i
    
    if __name__ == "__main__":
        for x in range(3):                              # 启动多个线程
            t=threading.Thread(target=foo,args=(3,))
            t.setDaemon(False)
            t.start()
            # 通过join方法让线程逐条执行
            # t.join()
    
    #output
    0
    00
    11
    1
    1
    2
    22
    3
    3
    3
    • 其实这就是三个线程并行运行同时输出,所以把结果都输出到一起引起。正是这种乱才整明白了确实三个函数在同时运行。
    • 如果想让结果看起来规则一些可以考虑使用join()方法,join()可以理解为, 函数是按顺序执行的. 但是有时候这并不是我们想要的. 虽然创建了多个线程,没有了并行还要多线程干嘛, 因此join方法不能随便乱用的

线程之Join方法正确姿势

  • 先看代码

    #!/usr/bin/env python
    #-*-coding:utf-8-*-
    
    import threading
    import time
    
    def foo(num):
        for i in range(num):
            time.sleep(0.5)
            print(i)
    
    if __name__ == "__main__":
        """
        创建一个列表,用于存储要启动多线程的实例
        """
        print("MainThread is running....")
        threads = []
        for x in range(3):
            t = threading.Thread(target=foo, args=(3,))
            # 把多线程的实例追加入列表,要启动几个线程就追加几个实例
            threads.append(t)
    
        for thr in threads:
            # 把列表中的实例遍历出来后,调用start()方法以线程启动运行
            thr.start()
    
        for thr in threads:
            """
            isAlive()方法可以返回True或False,用来判断是否还有没有运行结束
            的线程。如果有的话就让主线程等待线程结束之后最后再结束。
            """
            if thr.isAlive():
                thr.join()
        print("MainThread over")
    • t.setDaemon()方法的时候我们知道,主线程相当于程序的主运行流程。程序运行的时候最先启动的一定就是主线程,主线程负责拉起子线程用于干活。例子中运行函数foo()线程其实都是子线程。因此可以说多线程其实就是多个子线程。那么程序运行完最后一个退出的也肯定就是主线程。因此上例中最后再遍历一遍threads列表的目的就是查看还是否有没有退出的子线程,只要还有子线程是活的,没有退出。通过join()方法强制程序流程不可以走到主线程退出的那个步骤。只有等子线程都退出之后,才能根据join()方法的规则顺序执行到主线程退出的步骤。即最后 输出 MainThread over

线程锁(Lock)

  • 多线程和多进程最大的不同在于,多进程中,同一个变量,各自有一份拷贝存在于每个进程中,互不影响,而多线程中,所有变量都由所有线程共享,所以,任何一个变量都可以被任何一个线程修改,因此,线程之间共享数据最大的危险在于多个线程同时改一个变量,把内容给改乱了。

  • 一个混乱的例子

    #!/usr/bin/env python
    #-*-coding:utf-8-*-
    import time
    import  threading
    
    # 假定这是你的银行存款:
    balance = 0    # 余额
    
    def change_it(m):
       '''正常情况下: 存多少,取多少,金额应该不变'''
        global balance
        balance = balance + m
        balance = balance - m
    
    def run_thread(n):
        for i in range(100000):
            change_it(n)
    
    if __name__ == "_mian__":        
        t1 = threading.Thread(target=run_thread, args=(3,))
        t2 = threading.Thread(target=run_thread, args=(4,))
        t1.start()
        t2.start()
        t1.join()
        t2.join()
        print(balance)
    • 定义了一个共享变量balance,初始值为0,并且启动两个线程,先存后取,理论上结果应该为0,但是,由于线程的调度是由操作系统决定的,当t1、t2交替执行时,只要循环次数足够多,balance的结果就不一定是0了。

      原因是因为高级语言的一条语句在CPU执行时是若干条语句 ,即使一个简单的计算:

      balance = balance + x

      也分两步:可看以下两步

      x = balance + n
      balance = x

      数据错误的原因:是因为修改 balance

      需要多条语句,而执行这几条语句时,线程可能中断,从而导致多个线程把同一个对象的内容改乱了。

      两个线程同时一存一取,就可能导致余额不对,你肯定不希望你的银行存款莫名其妙地变成了负数,所以,我们必须确保一个线程在修改balance的时候,别的线程一定不能改。

    • 如果我们要确保balance计算正确,就要给change_it()上一把锁,当某个线程开始执行change_it()时,我们说,该线程因为获得了锁,因此其他线程不能同时执行change_it(),只能等待,直到锁被释放后,获得该锁以后才能改。由于锁只有一个,无论多少线程,同一时刻最多只有一个线程持有该锁,所以,不会造成修改的冲突。创建一个锁就是通过threading.Lock()来实现:

  • 为线程上一把锁

    #!/usr/bin/env python
    #-*-coding:utf-8-*-
    
    import time
    import threading
    
    # 假定这是你的银行存款:
    balance = 0    # 余额
    
    lock = threading.Lock()
    
    def change_it(m):
       '''正常情况下: 存多少,取多少,金额应该不变'''
        global balance
        balance = balance + m
        balance = balance - m
    
    def run_thread(n):
        for i in range(100000):
            lock.acquire()
            try:
                # 放心地改吧:
                change_it(n)
            finally:
                # 改完了一定要释放锁:
                lock.release()
    
    if __name__ == "_mian__":        
        t1 = threading.Thread(target=run_thread, args=(3,))
        t2 = threading.Thread(target=run_thread, args=(4,))
        t1.start()
        t2.start()
        t1.join()
        t2.join()
        print(balance)
    • 当多个线程同时执行lock.acquire()时,只有一个线程能成功地获取锁,然后继续执行代码,其他线程就继续等待直到获得锁为止。
    • 获得锁的线程用完后一定要释放锁,否则那些苦苦等待锁的线程将永远等待下去,成为死线程。所以我们用try...finally来确保锁一定会被释放。
    • 好处: 确保了某段关键代码只能由一个线程从头到尾完整地执行,比如多线程操作数据库
    • 坏处:首先是阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了; 其次,由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁,导致多个线程全部挂起,既不能执行,也无法结束,只能靠操作系统强制终止。

总结

  • 如何创建一个线程?
    • 使用 threading.Thread , 参数包含 target, args, name 等
  • 如何创建多线程?
    • 使用 for 语句
  • 什么是守护线程, 什么是主线程?
    • t.setDaemon(True) 表示的是后台线程, 表示程序流程(主线程)跑完之后直接就关闭了,然后退出了,根本不管子线程是否执行完
    • 默认t.setDaemon(False), 表示前台线程,主线程执行过程中,子线程也在进行,主线程执行完毕后,等待子线程都执行完成后,程序才会停止.
  • join() 方法 使用正确姿势: 使用线程池, 谨慎使用
  • 线程锁: threading.Lock(),解决线程间共享内存,同时对一个变量进行修改时造成数据混乱, 应用有: 比如多个多个线程对数据库同一个数据进行修改

参考

python 并发执行之多线程
Python3 多进程和多线程

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

python线程入门

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

python线程入门

目录 python线程入门 线程与进程 线程 总结 参考 python线程入门正常情况下,我们在启动一个程序
2023-01-30

python爬虫入门八:多进程/多线程

引用虫师的解释:计算机程序只不过是磁盘中可执行的,二进制(或其它类型)的数据。它们只有在被读取到内存中,被操作系统调用的时候才开始它们的生命期。进程(有时被称为重量级进程)是程序的一次执行。每个进程都有自己的地址空间,内存,数据栈以及其它记
2023-01-30

Python入门学习路线

Python技术路径中包含入门知识、Python基础、Web框架、基础项目、网络编程、数据与计算、综合项目七个模块。路径中的教程将带你逐步深入,学会如何使用 Python 实现一个博客,桌面词典,微信机器人或网络安全软件等。完成本路径的基础
2023-01-30

python开发之thread线程基础实例入门

本文实例讲述了python开发之thread线程基础。分享给大家供大家参考,具体如下: 说到线程,我们要知道啥是串行,啥是并行程序 举个例子: 串行程序,就是一个一个的执行程序#python threading import time ''
2022-06-04

好程序员Python学习路线之python爬虫入门

  好程序员Python学习路线之python爬虫入门,随着网络的迅速发展,万维网成为大量信息的载体,如何有效地提取并利用这些信息成为一个巨大的挑战。搜索引擎(Search Engine),例如传统的通用搜索引擎AltaVista,Yaho
2023-06-02

Python入门教程(二)

今天讲编程思维。  可能这对初次接触编程的人有用——我不是不想切入正题,我只是想强调根本没什么正题,我可能在其他文章里提过这一点。“编程语言就是语法糖”,可能你不知道什么是语法糖,但是知道的人也未必认同我。我不保证你们能听懂……python
2023-01-31

Python NLP 入门教程

本文简要介绍Python自然语言处理(NLP),使用Python的NLTK库。NLTK是Python的自然语言处理工具包,在NLP领域中,最常使用的一个Python库。什么是NLP?简单来说,自然语言处理(NLP)就是开发能够理解人类语言的
2023-01-31

Python编程入门(一)

Python编程入门(一)=========================================================================================概述:===============
2023-01-31

python jupyter入门教程

目录1.jupyter2.jupyter基础操作2.1windows更新pip库2.2jupyter安装2.3初次启动jupyter2.4设置密码进入jupyter3.创建一个jupyter文本4.jupyter文本的用法4.1保存和下载文
2022-06-02

python入门教程(一)

我们依然不讲代码,而是先说命令行。  为什么命令行如此重要?之前说到,命令行是你和电脑对话的地方。你可以用句子的方式把信息发给电脑,电脑再以句子的方式给你回应。在编程领域,有些消息只能用命令行告诉电脑——或许是编程人员早就习惯了,或许打字更
2023-01-31

python入门教程(零)

(本文针对Windows)  Python是什么?是一种编程语言。编程语言是什么?就是和机器说话的方式。编译器和解释器好比翻译,把你的话翻成机器听得懂的。但是这些翻译不怎么智能(虽然也有高下),你必须说一套很机械的官腔,他们才帮你翻译——但
2023-01-31

python pygame入门教程

目录一、安装二、第一个代码实例三、绘制一个矩形框四、绘制矩形框的进阶版本五、绘制一条直线六、绘制一条弧线一、安装 在 cmd 命令中输入: pip install pygame 即可安装成功了 二、第一个代码实例 代码快里面有注释,想必大家
2022-06-02

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录