多线程面试题汇总

一、多线程

1、线程的生命周期

在这里插入图片描述
1、线程的创建:t=threading.Thread()
2、就绪状态:已经获得了除CPU之外的其他资源,正在参与调度,等待被执行,当调度完成之后,立即运行
3、启动状态:获得了CPU时间片段,正在运行
4、等待\阻塞状态:遇到time.sleep()时,会阻塞,暂时不参与调度,等待事件发生
5、中止状态:线程运行结束,run函数运行结束,等待系统回收其线程资源。

2、线程的创建(函数创建)

在这里插入图片描述
在这里插入图片描述

3、线程的创建(使用类)

t=MyThread(name=s[i]) 创建线程,里面的参数代表线程的名字,如果不传,系统会默认有一个名字
在这里插入图片描述

4、守护线程

当我们在程序运行中,执行一个主线程,如果主线程又创建一个子线程,主线程和子线程就分兵两路,分别运行,那么当主线程完成想退出时,会检验子线程是否完成。如果子线程未完成,则主线程会等待子线程完成后再退出。但是有时候我们需要的是只要主线程完成了,不管子线程是否完成,都要和主线程—起退出,这时就可以用setDaemon方法
在这里插入图片描述
输出结果:线程2还没有完整的执行完毕,遇到守护线程就终止执行了。
在这里插入图片描述
t.setDaemon(True) 当前的子线程设置为守护线程
守护线程:随着主线程的终止而终止,不管当前主线程下有多少子线程没有执行完毕,都会终。

二、全局解释器锁

1、GIL锁不是python的特点。而是cpython的特点。

每个线程在执行的时候都需要先获取GIL,保证同一时刻只有一个线程可以执行代码,即同一时刻只有一个线程使用CPU。在CPython中,每一个Python线程执行前都需要去获得GIL锁,获得该锁的线程才可以执行,没有获得的只能等待,当具有GIL锁的线程运行完成后,其他等待的线程就会去争夺GIL锁,这就造成了,在Python中使用多线程,但同一时刻下依旧只有一个线程在运行,所以Python多线程其实并不是「并行」的,而是「并发」。

1、使用单线程实现累加到500000000

import time,threading


def task(n):
    sum=0
    while sum<n:
        sum+=1
    print(f'最后累加哦结果为:{
     
     sum}')



if __name__ == '__main__':
    # 单线程
    start=time.time()
    task(500000000)
    end=time.time()
    print(f'单线程结束后,一共运行的时间为:{
     
     end-start}')

在这里插入图片描述

2、使用多线程实现累加到500000000

import time,threading


def task(n):
    sum=0
    while sum<n:
        sum+=1
    print(f'最后累加哦结果为:{
     
     sum}')



if __name__ == '__main__':
    # 多线程
    start = time.time()
    t1=threading.Thread(target=task,args=(250000000,))
    t2=threading.Thread(target=task,args=(250000000,))

    t1.start()
    t2.start()

    t1.join()
    t2.join()
    end=time.time()
    print(f'单线程结束后,一共运行的时间为:{
     
     end-start}') # todo 15.777813196182251

在这里插入图片描述
发现问题:两个线程同时执行并不能比单个线程的执行快
由此发现:CPU密集型(计算密集型)任务采用多线程执行并不能提高计算速度

3、总结

GIL解决办法:

  • 使用其他语言写的python解析器(不推荐,还是用python官方的CPython好)
    • JPython、pypy
  • 不使用多线程,使用多进程-进程里面加协程实现多任务来充分利用多核CPU(推荐)
  • 即使存在GIL,在有IO等待操作的程序中,还是多线程快;当然没有资源等待的还是使用单线程快(科学计算、累加等等)

但是需要注意的是线程有了GIL后并不意味着使用python多线程时不需要考虑线程安全,GIL的存在是为了方便使用C语言CPython解释器的编写者,而顶层使用python时依旧要考虑线程安全。

三、线程安全

当多个线程同时访问一个对象时,不管如何计算,如果调用这个对象的行为都可以获得正确的结果,那就称这个对象时线程安全的。如果出现了“脏数据”。则线程不安全。
脏数据:产生脏数据的原因是,当一个线程在对数据进行修改时,修改到一半时另一个线程读取了未经修改的数据并进行修改。

如何避免脏数据的产生呢?一个办法就是用join方法,即先让一个线程执行完毕再执行另一个线
程。但这样的本质是把多线程变成了单线程,失去了多线程的意义。另一个办法就是用线程锁。

1、多线程之数据混乱问题

在这里插入图片描述
在这里插入图片描述
但是当我把累加次数设置小,就不会出现数据混乱问题
在这里插入图片描述
数据混乱的原因:
cpu分成多个时间片段,启动10线程,分配10

评论 49
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

敲代码敲到头发茂密

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值