线程 Thread类 GIL锁 信号量 Event事件

线程的开启方法

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

from threading import Thread


def task():
    print('A child thread')


if __name__ == '__main__': # 这里是可以不用写的,但是规范起见还是写了
    t = Thread(target=task)
    t.start()
    print('==>main thread')

GIL锁

"""

 1. Python在设计之初就考虑到要在主循环中,同时只有一个线程在执行
 2. Python 解释器中可以“运行”多个线程,但在任意时刻只有一个线程在解释器中运行。





 1、GIL锁它是在python解释器中的, 只在cpython中有, pypy解释器是没有GIL锁的,
 2、起一个垃圾回收线程, 一个是正常执行的线程
 3、设置了一把锁(GIL锁),  一个线程要想执行,必须拿到这把锁
 4、同一时刻,开启一个进程,一个进程中可以有多个线程, 只能有一个线程在执行


 5、如果是计算密集型:要开进程
 6、如果是io密集型:要开线程
"""

进程与线程的比较

image

线程与进程的区别可以归纳为以下4点:

  1. 地址空间和其它资源(如打开文件):进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。
  2. 通信:进程间通信IPC,线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据的一致性。
  3. 调度和切换:线程上下文切换比进程上下文切换要快得多。
  4. 在多线程操作系统中,进程不是一个可执行的实体。

进程消耗的资源比线程要大的多,相对的,调用起来也比线程要慢

# 进程调用时间演示
import time
from multiprocessing import Process


def task():
    time.sleep(1)
    print('A child process')


if __name__ == '__main__':
    start = time.time()
    p = Process(target=task)
    p.start()
    p.join()
    print('master process')
    print(time.time() - start)

# 输出结果
# A child process
# master process
# 1.069324016571045
# 线程调用时间演示
import time
from threading import Thread


def task():
    time.sleep(1)
    print('A child thread')


if __name__ == '__main__':
    start = time.time()
    t = Thread(target=task)
    t.start()
    t.join()
    print('==>main thread')
    print(time.time()-start)
# 输出结果
# A child thread
# ==>main thread
# 1.005803108215332

线程间的数据是共享的

def task():
  global n
  n=0
  
  
if __name__ == '__main__':
  n=1
  t=Thread(target=task)
  t.start()
  t.join()
  print('主',n) # 查看结果为0,因为同一进程内的线程之间共享进程内的数据

Thread类的方法

t.is_alive() # 返回线程是否活动
t.getName()  # 获取线程名
t.setName()  # 更新线程名
threading.currentThread() # 返回当前的线程变量
threading.enumerate() # 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程
threading.activeCount() # 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果

守护线程

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
import random

def task(lock):
   #上锁
   lock.acquire()
   global n
   # 10个线程同时涌入导致数据不安全
   time.sleep(random.random())
   n -= 1
   # 释放锁
   lock.release()


if __name__ == '__main__':
   start = time.time()
   lock = Lock()
   n = 100
   l = []
   for i in range(10):
       t = Thread(target=task,args=(lock,))
       t.start()
       l.append(t)
   for j in l:
       j.join()
   print('运算完毕:n = %s' %n)
   print(time.time()-start)

信号量

from threading import Thread,Semaphore
import time


def task(i, sm):
    # 上锁
    sm.acquire()
    print("%s:这个人开始上厕所了" % i)
    time.sleep(3)
    print("%s:这个人上完了" % i)
    # 释放锁
    sm.release()

# Semaphore:信号量可以理解为多把锁,同时允许多个线程来更改数据
if __name__ == '__main__':
    sm = Semaphore(2)  #
    for i in range(10):
        t = Thread(target=task, args=(i, sm))
        t.start()

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 16:16  popopop  阅读(27)  评论(0)    收藏  举报