3月30日课后总结

发布时间 2023-04-01 14:43:02作者: 橘子熊何妨

3/30课后总结

线程理论

"""
	进程只是一个过程,不会实际做事,做事的是线程。我们需要开启一个进程在进程里面开启线程,进程里至少有一个线程,可以有多个线程
"""
# 进程是资源分配的基本单位,线程是CPU执行的最小单位
# 当进程中只有一个线程的时候,这个线程叫主线程这个线程可以开启多个子线程
# 操作系统来调度进程和线程,程序员级别是不能调度他们的,程序员能调度的是协程(用户态)
# 资源占用:进程   >>> 线程  >>> 协程
# 在python中,我们一般开多进程,而不开多线程,在其他语言中,都是选择开多线程

如何开启线程(线程类)

from threading import Thread

def test():
    print(1)
# 与进程用法差不多
if __name__ == '__main__':
    t = Thread(target=test)
    t.start()  # 开线程,在Windows中可以不写main但是尽量写一下

守护线程

from threading import Thread
import time

def test():
    time.sleep(3)
    print(1)

if __name__ == '__main__':
    t = Thread(target=test)
    t.daemon = True  # 当daemon为True时,主进程结束子进程就结束
    t.start()
    print(123)

如何开启多线程

from threading import Thread  # 与开启多进程类似,只是消耗资源更少

def test(i):
    print(f'这是第{i}次')

if __name__ == '__main__':
    l = []
    for i in range(10):
        t = Thread(target=test,args=(i,))
        t.start()
        l.append(t)
    for j in l:
        j.join()
    print('end')

threading提供的方法

import threading
from threading import Thread
import time

def test():
    # time.sleep(3)
    print(threading.currentThread())  # 获取当前线程的对象
    print(threading.currentThread().getName())  # 获取当前线程的名字
    print(1)

if __name__ == '__main__':
    t = Thread(target=test)
    # t.daemon = True
    t.start()
    # t.join()  # 在子线程运行完毕后执行主线程
    # print(t.is_alive())  # 查看线程是否存活
    # print(t.name)  # 查看子线程名
    # t.setName('123')  # 给子线程改名
    # print(t.getName())  # 查看子线程名
    print(threading.currentThread())  # 获取当前线程的对象
    print(threading.currentThread().getName())  # 获取当前线程的名字
    print(123)

进程和线程的比较

1. 进程的开销要远远大于线程的开销
2. 线程之间的数据是相互通信的,严格的来说:同一个进程下的所有线程数据共享
3. 不同进程下的线程之间数据是不共享的---->如何让不同进程下的线程之间数据共享--->其实就是进程间通信

GIL全局解释器锁

Python在设计之初就考虑到要在主循环中,同时只有一个线程在执行
# 虽然 Python 解释器中可以“运行”多个线程,但在任意时刻只有一个线程在解释器中运行。
'''
	对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同一时刻只有一个线程在运行。
'''

1. python代码运行在解释器之上,有解释器来翻译执行
2. python解释器的种类有哪些?
	CPython  IPython PyPy Jython
3. GIL锁存在于CPython解释器中
4. 市面上目前绝大多数(95%)都使用的是CPython解释器
5. 起一个垃圾回收线程,在起一个正常执行代码的线程,当垃圾回收线程还没回收完毕,其他线程有可能会抢夺资源,这种情况在python设计之初就不允许的
6. python在设计之处,就在python解释器之上加了一把锁(GIL锁),加这个锁的目的是:同一时刻只能有一个线程执行,不能同时有多个线程执行,如果开了多个线程,那么,线程要想有执行权限,必须先拿到这把锁(GIL锁)
"""只需要记住:同一时刻多个线程只能有一个线程在运行,其他线程都处于等待状态"""


#########################理解记忆部分########################################
1. python有GIL锁的原因,同一个进程下多个线程实际上同一时刻,只有一个线程在执行
2. 只有在python上开进程用的多,其他语言一般不开多进程,只开多线程就够了
3. cpython解释器开多线程不能利用多核优势,只有开多进程才能利用多核优势,其他语言不存在这个问题
4. 8核cpu电脑,充分利用起我这个8核,至少起8个线程,8条线程全是计算--->计算机cpu使用率是100%,
5. 如果不存在GIL锁,一个进程下,开启8个线程,它就能够充分利用cpu资源,跑满cpu
6. cpython解释器中好多代码,模块都是基于GIL锁机制写起来的,改不了了---》我们不能用8个核,但我现在只能用1核,----》开启多进程---》每个进程下开启的线程,可以被多个cpu调度执行
7. cpython解释器:io密集型使用多线程,计算密集型使用多进程
	# -io密集型,遇到io操作会切换cpu,假设你开了8个线程,8个线程都有io操作---》io操作不消耗cpu---》一段时间内看上去,其实8个线程都执行了, 选多线程好一些
   
# -计算密集型,消耗cpu,如果开了8个线程,第一个线程会一直占着cpu,而不会调度到其他线程执行,其他7个线程根本没执行,所以我们开8个进程,每个进程有一个线程,8个进程下的线程会被8个cpu执行,从而效率高
'''计算密集型选多进程好一些,在其他语言中,都是选择多线程,而不选择多进程.'''

互斥锁

from threading import Thread,Lock
import time

n = 10

def test(lock):
    lock.acquire()
    global n
    temp = n
    time.sleep(1)
    n=temp-1
    lock.release()

if __name__ == '__main__':
    l = []
    lock = Lock()
    for i in range(10):
        t = Thread(target=test,args=(lock,))
        t.start()
        l.append(t)
    for j in l:
        j.join()
    print(n)