python学习day38笔记

线程

进程是操作系统调度的最小单位,一个进程最少有一个主线程,一个进程中可以开启多个线程
真正干活的是线程

具体类似于:
有一个食谱(线程)上面写好了整个做菜流程,做菜中间需要几个食材和佐料(数据),然后人按照食谱做菜,按照食谱做菜这一整个过程可以看做是个进程

进程是资源分配的最小单位,线程是cpu调度的最小单位

线程开启的花销远远小于进程,但是使用多进程可以利用多核的优势,多线程只能调用同一个核

开启线程

方法和开启进程类似

from threading import Thread

def task():
    print('我是子线程')

if __name__ == '__main__':
    t = Thread(target=task)
    t.start()
    print('这是主线程')

GIL锁

在python的设计中,在主循环内同时只能有一个线程在执行,在python解释器中可以并行多个线程
对python解释器的访问由全局解释器锁GIL来控制,正是这个锁能保证同一时刻只有一个线程在运行

1.GIL锁它是在python解释器中的,只在cpython中有,pypy解释器是没有GIL锁的
2.起一个垃圾回收线程,一个是正常执行的线程,如果有一个线程即将被垃圾回收线程回收时被正常执行的线程调用,数据就会不安全
3.这个时候就设置了一把锁(GIL锁),一个线程要想执行,必须拿到这把锁
4.同一时刻,开启一个进程,一个进程中可以有多个线程,但是只能有一个线程执行

计算密集型:开进程
# 计算密集型是计算多,是由cpu进行计算,用进程可以充分发挥cpu的多核优势
io密集型:开线程
# io密集不牵扯计算,中间切换线程的消耗远远小于切换进程的消耗

进程与线程的比较

线程

from threading import Thread
import time
def task():
    print('我是子线程')
    time.sleep(1)

if __name__ == '__main__':
    first = time.time()
    t = Thread(target=task)
    t.start()
    t.join()
    print('这是主线程')
    print(time.time() - first)
    
# 我是子线程
# 这是主线程
# 1.0059137344360352

进程

from multiprocessing import Process
import time
def task():
    print('我是子进程')
    time.sleep(1)

if __name__ == '__main__':
    first = time.time()
    t = Process(target=task)
    t.start()
    t.join()
    print('这是主进程')
    print(time.time() - first)
    
# 我是子进程
# 这是主进程
# 1.0809822082519531


进程之间切换的速度相比线程,简直像过年一样

线程之间的数据是共享的

from threading import Thread
def task():
    global n
    n = 3
if __name__ == '__main__':
    n = 0
    t = Thread(target=task)
    t.start()
    t.join()
    print(n)
    
# 3

Thread类的其他方法

is_alive()  # 返回线程是否活动
getName()  # 返回线程名
setName()  # 设置线程名
join()  # 与进程的join一样

threading.currentThread()
# 返回当前的线程变量
threading.enumerate()
# 返回一个包含正在运行的线程的list
threading.activeCount()
# 返回正在运行的线程数量,与len(threading.enumerate())结果一致

守护线程

setDaemon(True)  # 开启守护线程,主线程结束,子线程跟着结束,需要放在start前面

from threading import Thread
import time
def task():
    time.sleep(1)
    print('我是子线程')
if __name__ == '__main__':
    t = Thread(target=task)
    t.setDaemon(True)
    t.start()
    print('主线程')
    
# 主进程

互斥锁(同步锁)

from threading import Thread,Lock
import time
def task(lock):
    lock.acquire()  # 上锁
    global n
    temp = n
    time.sleep(1)
    n = temp - 1
    lock.release()  # 释放锁
    
if __name__ == '__main__':
    n = 10
    ll = []
    lock = Lock()
    for i in range(3):
        t = Thread(target=task, args=(lock, ))
        t.start()
        ll.append(t)

    for j in ll:
        j.join()

    print("主线程:", n)
    
# 主线程: 7

如果没有同步锁,在time.sleep(1)之后的一瞬间,所有线程都会取n的值然后进行计算,会产生并发线程的数据安全问题

信号量

from threading import Thread,Semaphore
import time

def task(i, sm):
    sm.acquire()  # 上锁
    print("%s:这个人开始上厕所了" % i)
    time.sleep(3)
    print("%s:这个人上完了" % i)
    sm.release()  # 释放锁
    
if __name__ == '__main__':
    sm = Semaphore(2)  # 允许两个线程同时执行
    for i in range(10):
        t = Thread(target=task, args=(i, sm))
        t.start()
        
Semaphore:信号量可以理解为多把锁,同时允许多个线程来更改数据

Event事件

from threading import Thread, Event
import time

def girl(event):
    print("都女士正在恋爱中...")
    time.sleep(3)
    print("都女生分手了")
    event.set()  # 发出分手的信号

def boy(i, event):
    print("渣男:%s正在等待都女生分手" % i)
    event.wait()  # 等待信号
    print("渣男:%s开始追了" % i)

if __name__ == '__main__':
    event = Event()
    t = Thread(target=girl, args=(event,))
    t.start()
    for i in range(10):
        b_t = Thread(target=boy, args=(i, event))
        b_t.start()
posted @ 2021-07-22 17:43  麋鹿的麋  阅读(33)  评论(0)    收藏  举报