精华内容
下载资源
问答
  • python多线程比单线程慢
    2022-07-13 04:59:34

    看到一个说多线程比单线程慢的帖子,我惊呆了

    赶紧测试了一下

    说多线程比单线程慢那兄弟就是喝高了!


    单线程和多线程分别进行 10*100万次运算
    得出结果,多线程速度远超单线程
    至于为什么 绝大多帖都说Python多线程是假的  可能是个底层问题,但既然叫多线程在多任务的条件下 就不可能比单线程慢,这是板上钉钉的

    至于​多进程就不用测试了,那玩意儿没啥好说的就是个复制自身 多开,优势在于便于资源管理,但我个人觉得是懒人操作,就多几行代码的事情而已 如果是资源较为复杂的情况可以用多开来代替多进程可能会是一个不错的解决方案

    import threading
    import time
    
    threadLock = threading.Lock()  # 创建锁
    
    # 定义一个 全局变量 用于查询 多线程是否完全退出
    q = 0
    def lock(args):  # 线程数 锁递增递减
        global q
        threadLock.acquire()  # 获取线程锁 保证线程不会同时进入
        q = q + args
        threadLock.release()  # 退出线程锁 保证线程不会同时进入
    
    # 定义一个 线程函数
    def testadd():
        lock(1)
        s = 0
        for i in range(int(1000000)):
            s += i
            s /= 2
        lock(-1)
        return s
    
    # 单线程 运行10 * 100万次计算
    a = 0
    c = 10
    time1 = time.perf_counter()
    while a < c:
        a += 1
        testadd()
    time2 = time.perf_counter()
    print('单线程:',f'{time2 - time1:.2f}' , '秒')
    
    # 多线程 运行10 * 100万次计算
    i = 0
    c = 10
    time1 = time.perf_counter()
    while i < c:
        i += 1
        t1 = threading.Thread(target=testadd)
        t1.start()
    time2 = time.perf_counter()
    while q == 0: #  循环判断运行中 线程数    当所有线程退出头跳出循环
        break
    print('多线程:', f'{time2 - time1:.2f}', '秒')
    

    更多相关内容
  • python多线程比单线程效率低的原因是:GIL python中有一个 GIL( Global Interpreter Lock),中文为:全局解释器锁 - 最开始时候设计GIL是为了数据安全。python为了数据安全设计了这个 GIL - 每个 CPU在同一时间...

    前言

    Python语言的标准实现叫作CPython,它分两步来运行Python程序

    • 步骤1:解析源代码文本,并将其编译成字节码(bytecode)
      • 字节码是一种底层代码,可以把程序表示成8位的指令
      • 从Python 3.6开始,这种底层代码实际上已经变成16位了
    • 步骤2:CPython采用基于栈的解释器来运行字节码
      • 字节码解释器在执行Python程序的过程中,必须确保相关的状态不受干扰,
      • CPython会用一种叫作全局解释器锁(global interpreter lock,GIL)的机制来实现运行的python程序的相关状态不受干扰

    GIL

    • GIL实际上就是一种互斥锁(mutual-exclusion lock,mutex),用来防止CPython的状态在抢占式的多线程环境(preemptive multithreading)之中受到干扰,因为在这种环境下,一条线程有可能突然打断另一条线程抢占程序的控制权。如果这种抢占行为来得不是时候,那么解释器的状态(例如为垃圾回收工作而设立的引用计数等)就会遭到破坏。
    • CPython要通过GIL阻止这样的动作,以确保它自身以及它的那些C扩展模块能够正确地执行每一条字节码指令。
    • GIL会产生一个很不好的影响。在C++与Java这样的语言里面,如果程序之中有多个线程能够分头执行任务,那么就可以把CPU的各个核心充分地利用起来。尽管Python也支持多线程,但这些线程受GIL约束,所以每次或许只能有一条线程向前推进,而无法实现多头并进。
    • 所以,想通过多线程做并行计算或是给程序提速的开发者,恐怕要失望了。
      • 并发 concurrency : 指计算机似乎能在同一时刻做许多不同的事情
      • 并行 parallelism : 指计算机确实能够在同一时刻做许多不同的事情

    多线程下的线程执行

    1. 获取GIL
    2. 执行代码直到sleep或者是 python虚拟机将其挂起。
    3. 释放 GIL

    多线程效率低于单线程原因

    • 如上我们可以知道,在 python中想要某个线程要执行必须先拿到 GIL这把锁,且 python只有一个 GIL,拿到这个 GIL才能进入 CPU执行, 在遇到 I/O操作时会释放这把锁。如果是纯计算的程序,没有 I/O 操作,解释器会每隔 100次操作就释放这把锁,让别的线程有机会 执行(这个次数可以通sys.setcheckinterval来调整)。所以虽然 CPython 的线程库直接封装操作系统的原生线程,但 CPython 进程做为一个整体,同一时间只会有一个获得了 GIL 的线程在跑,其它的线程都处于等待状态等着 GIL 的释放。
    • 而每次释放 GIL锁,线程进行锁竞争、切换线程,会消耗资源。并且由于 GIL锁存在,python里一个进程永远只能同时执行一个线程 (拿到 GIL的线程才能执行 ),这就是为什么在多核 CPU上, python的多线程效率并不高

    多线程效率低于或高于单线程原因

    • 相同的代码,为何有时候多线程会比单线程慢,有时又会比单线程快? 这主要跟运行的代码有关:
    • CPU密集型代码(各种循环处理、计数等等 ),在这种情况下,由于计算工作多, ticks计数很快就会达到 100阈值,然后触发 GIL的释放与再竞争 (多个线程来回切换当然是需要消耗资源的),所以 python下的多线程遇到 CPU密集型代码时,单线程比多线程效率高。
    • IO密集型代码 (文件处理、网络爬虫等 ),多线程能够有效提升效率单线程下有 IO操作会进行 IO等待,造成不必要的时间浪费。开启多线程能在线程 A等待时,自动切换到线程 B,可以不浪费 CPU的资源,从而能提升程序执行效率 。进行IO密集型的时候可以进行分时切换 所有这个时候多线程快过单线程

    如果 python想充分利用多核 CPU,可以采用多进程

    • 每个进程有各自独立的 GIL,互不干扰,这样就可以真正意义上的并行执行。
      在 python中,多进程的执行效率优于多线程 (仅仅针对多核 CPU而言 )。所以在多核 CPU下,想做并行提升效率,比较通用的方法是使用多进程,能够有效提高执行效率

    代码示例:

    # 多线程
    # 最后完成的线程的耗时
    # [TIME MEASURE] execute function: gene_1000_field took 3840.604ms
    @time_measure
    def mult_thread(rows):
        # 总行数
        rows = rows
        # 线程数
        batch_size = 4
        cell = math.ceil(rows / batch_size)
        # 处理数据生成
        print('数据生成中,线程数:' + str(batch_size))
        threads = []
        for i in range(batch_size):
            starts = i * cell
            ends = (i + 1) * cell
            file = f"my_data_{str(i)}.csv"
            # t = threading.Thread(target=gene_1000_field_test, args=(starts, ends, file))
            t = threading.Thread(target=gene_1000_field, args=(starts, ends, file))
            t.start()
            threads.append(t)
        # for t in threads:
        #     t.join()
    
    # 多进程
    # [TIME MEASURE] execute function: gene_1000_field took 1094.776ms
    # 执行时间和单个线程的执行时间差不多,目的达到
    @time_measure
    def mult_process(rows):
        # 总行数
        rows = rows
        # 线程数
        batch_size = 4
        cell = math.ceil(rows / batch_size)
        # 处理数据生成
        print('数据生成中,线程数:' + str(batch_size))
        process = []
        for i in range(batch_size):
            starts = i * cell
            ends = (i + 1) * cell
            file = f"my_data_{str(i)}.csv"
            # p = Process(target=f, args=('bob',))
            # p.start()
            # p_lst.append(p)
            # t = threading.Thread(target=gene_1000_field_test, args=(starts, ends, file))
            p = Process(target=gene_1000_field, args=(starts, ends, file))
            p.start()
            process.append(p)
    
    

    参考文章:

    1. https://www.cnblogs.com/caopeiyang/p/9418897.html
    2. https://www.cnblogs.com/nickchen121/p/11130256.html
    展开全文
  • 然后就动手写了一个多线程,但是发现速度甚至不及单线程,甚至还要更。Excuse Me???? 然后就去查看了一下别的大佬怎么讲。 python线程原理(敲黑板) 下面引入一个概念GIL。我们看官方给出的解释: In CPython...
  • 深入理解Python 多线程

    2020-12-17 03:33:42
    利用Python多线程,只是利用CPU上下文切换的优势,看上去像是并发,其实只是个单线程,所以说他是假的单线程。 那么什么时候用多线程呢? 首先要知道: io操作不占用CPU 计算操作占CPU,像2+5=5 Python多线程...
  • 主要介绍了Python单线程多线程和多进程效率对比,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • Python多线程在io方面比单线程还是有优势,但是在多线程开发时,少不了对文件的读写操作。在管理多个线程对同一文件的读写操作时,就少不了文件锁了。 使用fcntl 在linux下,python的标准库有现成的文件锁,来自于...
  • 一个程序的执行时间就会主要花费在等待次查询返回结果,在这个过程中cpu无疑是处于等待io的空闲状态的,这样既浪费了cpu资源,又花费了大量时间(当然这里主要说多线程,批量查询不在考虑范围,总会存在不能批量...
  •  资料显示,如果多线程的进程是CPU密集型的,那多线程并不能有多少效率上的提升,相反还可能会因为线程的频繁切换,导致效率下降,推荐使用多进程;如果是IO密集型,多线程进程可以利用IO阻塞等待时的空闲时间执行...
  • 本文实例为大家分享了python多线程同步之文件读写控制的具体代码,供大家参考,具体内容如下 1、实现文件读写的文件ltz_schedule_times.py #! /usr/bin/env python #coding=utf-8 import os def ReadTimes(): res ...
  • 多代理还好说,再写个爬虫爬一堆下来就好,多线程可就麻烦多了,多线程一旦发出去了,基本等同于失控的状态,你无法去结束或者是重启一个线程,最多只能是获取线程的信息,没有实际的控制权,而且Python官方也没有...
  • 单线程实现个定时器 NewTimer.py复制代码 代码如下:#!/usr/bin/env python from heapq import *from threading import Timerimport threadingimport uuidimport timeimport datetimeimport sysimport math global ...
  • 主要介绍了Python多线程处理,结合实例形式总结分析了Python进程、多进程、多线程等相关操作技巧与注意事项,需要的朋友可以参考下
  • 先了解下CPU的简单运行原理:它运行速度非常快,1s内可以运行成千上万次,一个核心可以把1s切分成...再了解下单线程和多线程的区别:先看下单进程,顾名思义,就是一条进程,类似于单向公路上只有一条车道,每次只能...

    先了解下CPU的简单运行原理:

    它运行速度非常快,1s内可以运行成千上万次,一个核心可以把1s切分成成千上万个时间片段,这个核心确实同时只能运行一个任务;但是可以将多个任务交替执行,比如上一个时间片段内运行A任务,下个时间片段可以运行B任务,交替执行,因为时间片段很短,所以感觉就是同时在进行了。

    再了解下单线程和多线程的区别:

    先看下单进程,顾名思义,就是一条进程,类似于单向公路上只有一条车道,每次只能过一辆车,多进程则表示多个车道,可以同时过多辆车;那么单线程和多线程意义严格上来说不是进程这样的理解,因为进程内的线程同一时间点只能运行一个,不存在同时进行,CPU给我们的感觉的同时进行,只是它运行的非常快,交替执行多个线程差别可能是毫秒、微秒的区别,所以感觉不到差别,他们在同时进行。

    接着就产生了单线程和多线程的疑惑:

    既然上述说了,多线程并不是多个线程并发在同一时间点运行,而是CPU有计划的交替执行各个多线程,那多线程的优势在哪里?比如python里,从上运行到下调用多次同一个函数是个单线程,和把几次调用函数写成多线程,依据上述理论,这里的CPU运行时间并没有变快啊,因为多线程不能并发运行,也是一个个线程类交替执行完成啊,甚至多线程可能更慢,因为它还要花时间去管理交替执行任务上,不要怀疑,事实上就是如此,那么我们使用多线程的意义在哪里?

    这里需要了解下GIL:

    Python是解释型语言,那么它在运行的时候就需要解释器了,简单描述下GIL,即global interpreter lock,全局解释器锁,就是python在运行的时候会锁定解释器,就是说在运行的时候只能是一个线程,锁死了,切换不了;每个线程在运行之前都要申请GIL,那么就必须要等上一个线程释放这把锁你才可以申请到,然后执行代码,执行完后,你再交给下一个线程,让它去执行代码,过程如下:

    设置GIL -> 切换到一个线程去执行 -> 运行 -> 把线程设置为睡眠状态 -> 解锁GIL

    然后再次重复以上步骤。

    IO密集型任务多线程比单线程要快太多:

    貌似多线程比单线程还要耗CPU,而且运行速度又没变快,甚至更慢,这是相对于计算密集型任务(要进行大量的计算,消耗CPU资源,比如计算圆周率、对视频进行高清解码等等,全靠CPU的运算能力)来说的,像这类计算密集型任务由于主要消耗CPU资源,python用多线程效率不会提高,甚至是会更慢,原理见上述GIL;

    还有一种IO密集型任务,涉及到网络、磁盘IO的任务都是IO密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待IO操作完成(因为IO的速度远远低于CPU和内存的速度),99%的时间都花在IO上,花在CPU上的时间很少;

    原谅我不自觉的想到了爬虫,爬虫是典型的IO密集型任务,多线程的发送请求情况下:发送一个请求到收到服务器的响应数据取决于网络的快慢,那么发送一个请求之后就是等待服务器的响应了,期间会释放GIL锁,其他线程就可以申请到这把锁,进行发送请求了,重复上述操作直到最后一个请求,那么就等同于非常短的时间内,CPU发送了多个请求,接下来就是等待服务器的响应;那么如果是单线程呢?它发送一个请求后就在那里等着服务器响应,直到服务器有返回数据到客户端后,才会释放GIL锁,接着继续下一个请求,只能是一个个的排队,直到最后一个执行完,显而易见,这里的线程相当并发请求了,比单线程要快的多。

    综上所述:

    在处理计算密集型任务时,python的多线程劣与单线程,性能表现比单线程要差;

    在处理IO密集型任务时,python的多线程优与单线程,性能表现比单线程要好太多;

    展开全文
  • 由于机器上线程数量太,可能要查看的线程的信息在top命令当前屏幕上显示不出来可以通过如下方式查看 在top命令下输入:u 接下来会提示输入用户名,就可以查看该用户所执行的所有线程 Which user (blank for all): ...
  • 之前写过一篇爬取小说的博客,但是单线程爬取速度太了,之前爬取一部小说花了700多秒,1秒两章的速度有点让人难以接受。 所以弄了个多线程的爬虫。 这次的思路和之前的不一样,之前是一章一章的爬,每爬一章就写入...
  • 多线程不一定比单线程快在Python中,可以通过多进程、多线程和多协程来实现多任务。难道多线程就一定比单线程快?下面我用一段代码证明我自己得观点。'''@Author: Runsen@微信公众号: Python之王@博客:...

    pyrhon视频教程栏目介绍多线程是否真的比单线程快。

    66efcd0419141a93899f63f0aa3d1bc6.png

    事实上,Python 多线程另一个很重要的话题叫,GIL(Global Interpreter Lock,即全局解释器锁)。

    多线程不一定比单线程快

    在Python中,可以通过多进程、多线程和多协程来实现多任务。难道多线程就一定比单线程快?

    下面我用一段代码证明我自己得观点。'''

    @Author: Runsen

    @微信公众号: Python之王

    @博客: https://blog.csdn.net/weixin_44510615

    @Date: 2020/6/4

    '''import threading, timedef my_counter():

    i = 0

    for _ in range(100000000):

    i = i+1

    return Truedef main1():

    start_time = time.time() for tid in range(2):

    t = threading.Thread(target=my_counter)

    t.start()

    t.join() # 第一次循环的时候join方法引起主线程阻塞,但第二个线程并没有启动,所以两个线程是顺序执行的

    print("单线程顺序执行total_time: {}".format(time.time() - start_time))def main2():

    thread_ary = {}

    start_time = time.time() for tid in range(2):

    t = threading.Thread(target=my_counter)

    t.start()

    thread_ary[tid] = t for i in range(2):

    thread_ary[i].join() # 两个线程均已启动,所以两个线程是并发的

    print("多线程执行total_time: {}".format(time.time() - start_time))if __name__ == "__main__":

    main1()

    main2()复制代码

    运行结果单线程顺序执行total_time: 17.754502773284912多线程执行total_time: 20.01178550720215复制代码

    我怕你说我乱得出来得结果,我还是截个图看清楚点

    a8165595d3454738440e1fb17f0502a1.png

    这时,我怀疑:我的机器出问题了吗?其实不是这样,本质上来说Python 的线程失效了,没有起到并行计算的作用。

    Python 的线程,的确封装了底层的操作系统线程,在 Linux 系统里是 Pthread(全称为 POSIX Thread),而在 Windows 系统里是 Windows Thread。另外,Python 的线程,也完全受操作系统管理,比如协调何时执行、管理内存资源、管理中断等等。

    GIL不是Python的特性

    GIL 的概念用简单的一句话来解释,就是任一时刻,无论线程多少,单一 CPython 解释器只能执行一条字节码。这个定义需要注意的点:

    首先需要明确的一点是GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念。

    C++是一套语言(语法)标准,但是可以用不同的编译器来编译成可执行代码。有名的编译器例如GCC,INTEL C++,Visual C++等。

    Python也一样,同样一段代码可以通过CPython,PyPy,Psyco等不同的Python执行环境来执行。

    其他 Python 解释器不一定有 GIL。例如 Jython (JVM) 和 IronPython (CLR) 没有 GIL,而 CPython,PyPy 有 GIL;

    因为CPython是大部分环境下默认的Python执行环境。所以在很多人的概念里CPython就是Python,也就想当然的把GIL归结为Python语言的缺陷。所以这里要先明确一点:GIL并不是Python的特性,Python完全可以不依赖于GIL

    GIL本质就是一把互斥锁

    GIL本质就是一把互斥锁,既然是互斥锁,所有互斥锁的本质都一样,都是将并发运行变成串行,以此来控制同一时间内共享数据只能被一个任务所修改,进而保证数据安全。

    可以肯定的一点是:保护不同的数据的安全,就应该加不同的锁。

    GIL 的工作原理:比如下面这张图,就是一个 GIL 在 Python 程序的工作示例。其中,Thread 1、2、3 轮流执行,每一个线程在开始执行时,都会锁住 GIL,以阻止别的线程执行;同样的,每一个线程执行完一段后,会释放 GIL,以允许别的线程开始利用资源。

    03122cb0e0c81c96a0f51931909d8759.png

    计算密集型

    计算密集型任务的特点是要进行大量的计算,消耗CPU资源。

    我们先来看一个简单的计算密集型示例:'''

    @Author: Runsen

    @微信公众号: Python之王

    @博客: https://blog.csdn.net/weixin_44510615

    @Date: 2020/6/4

    '''import time

    COUNT = 50_000_000def count_down():

    global COUNT while COUNT > 0:

    COUNT -= 1s = time.perf_counter()

    count_down()

    c = time.perf_counter() - s

    print('time taken in seconds - >:', c)

    time taken in seconds - >: 9.2957003复制代码

    这个是单线程, 时间是9s, 下面我们用两个线程看看结果又如何:'''

    @Author: Runsen

    @微信公众号: Python之王

    @博客: https://blog.csdn.net/weixin_44510615

    @Date: 2020/6/4

    '''import timefrom threading import Thread

    COUNT = 50_000_000def count_down():

    global COUNT while COUNT > 0:

    COUNT -= 1s = time.perf_counter()

    t1 = Thread(target=count_down)

    t2 = Thread(target=count_down)

    t1.start()

    t2.start()

    t1.join()

    t2.join()

    c = time.perf_counter() - s

    print('time taken in seconds - >:', c)

    time taken in seconds - >: 17.110625复制代码

    我们程序主要的操作就是在计算, CPU没有等待, 而改为多线程后, 增加了线程后, 在线程之间频繁的切换,增大了时间开销, 时间当然会增加了。

    还有一种类型是IO密集型,涉及到网络、磁盘IO的任务都是IO密集型任务,这类任务的特点是CPU消耗很少,任务的大部分时间都在等待IO操作完成(因为IO的速度远远低于CPU和内存的速度)。对于IO密集型任务,任务越多,CPU效率越高,但也有一个限度。常见的大部分任务都是IO密集型任务,比如Web应用。

    总结:对于io密集型工作(Python爬虫),多线程可以大幅提高代码效率。对CPU计算密集型(Python数据分析,机器学习,深度学习),多线程的效率可能比单线程还略低。所以,数据领域没有多线程提高效率之说,只有将CPU提升到GPU,TPU来提升计算能力。

    展开全文
  • Python单线程/多线程

    千次阅读 2021-12-19 07:35:15
    利用Python多线程,只是利用CPU上下文切换的优势,看上去像是并发,其实只是单线程。 import threading import time def test1(): for i in range(10000000): a = 100 - i def test2(): threads = [] t1...
  • 对于python 多线程的理解,我花了很长时间,搜索的大部份文章都不够通俗易懂。所以,这里力图用简单的例子,让你对多线程有个初步的认识。 单线程  在好些年前的MS-DOS时代,操作系统处理问题都是单任务的,我想做...
  • 批量爬虫下载时,单线程下载文件有时有时快。写一个多线程分块下载文件工具。网上的一些代码可能会有些奇怪的问题,用的是类全局变量打开文件但在多线程中并未加锁,会导致文件有一定几率出现大小和源文件不同,...
  • 逻辑处理上分成了多个模块,为了提高效率,前一个模块处理完调用后一个模块操作时使用多线程 我这里遇到的情形是前面取数据后面存到mysql,发现单线程效率很低,改为取数据后开线程存到mysql 开启线程之后性能提升一...
  • Python单线程多线程

    2021-01-14 00:03:53
    最近一直在学习爬虫的相关知识,目前学习到了单线程多线程这一块,把自己的学习经历分享出来顺便也做个笔记。一.单线程操作单线程操作就是我们日常写代码时的操作,为了比较出和多线程的区别,以下为其对比。#使用...
  • “消息队列”是在消息的传输过程中保存消息的容器。...1.threading+Queue实现线程队列 #!/usr/bin/env python import Queue import threading import time queue = Queue.Queue() class ThreadNum(threading
  • 本文实例讲述了Python多线程Threading、子线程与守护线程。分享给大家供大家参考,具体如下: 线程与进程: 线程对于进程来说,就好似工厂里的工人,分配资源是分配到工厂,工人再去处理。 线程是被系统独立调度和...
  • 而且由于线程之间切换的开销导致多线程往往实际的单线程还要,所以在 python 中计算密集型任务通常使用多进程,因为各个进程有各自独立的 GIL,互不干扰。 而在 IO 密集型任务中,CPU 时常处于等待状态,操作...
  • 单线程执行 python的内置模块提供了两个内置模块:thread和threading,thread是源生模块,threading是扩展模块,在thread的基础上进行了封装及改进。所以只需要使用threading这个模块就能完成并发的测试 实例 创建...
  • python3 多线程篇1

    2020-12-21 06:06:45
    遂本人学习了一下Python中的多线程/多进程知识,经过一番学习找到了Python中编写并行程序的最好模式,记录如下: Python3 通过两个标准库 _thread 和 threading 提供对线程的支持,不过threading基本可以完虐_thread...
  • 下面,通过一个简单的例子,来把多线程单线程执行任务的耗时做个比较 import time import threading # 音乐播放器 def music(func, loop): for i in range(loop): print("I was listening to %s the %d time! ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 137,496
精华内容 54,998
热门标签
关键字:

python多线程比单线程慢