线程的那些事儿

it2022-05-08  10

一、线程的基本概念:

  

  线程被称为轻量级进程。

  计算机的执行单位以线程为单位。计算机的最小可执行是线程。

  进程是资源分配的基本单位。线程是可执行的基本单位,是可被调度的基本单位。

  线程不可以自己独立拥有资源。线程的执行必须依赖所属进程中的资源。

  进程中必须至少有一个线程。

  由于GIL(全局解释锁,只在Cpython中有),导致线程没有真正的并行。

  线程分为用户级线程和内核级线程。

二、进程由  代码段、数据段、PCB(进程控制块)组成

  线程由  代码块、数据块、TCB(线程控制块)组成

三、线程和进程的比较

  thread -- 线程

  导入线程模块的两种方法:

  import   threading

  from   threading   import  Thread

  (1) cpu 切换进程比切换线程 慢很多。在python中,如果IO操作过多的话,使用多线程最好了。

  (2) 在同一进程内,所有线程共享这个进程的pid,也就是说所有的线程共享所属进程的资源和内存。

  (3) 在同一个进程内,所有线程共享该进程中的全局变量

  (4) 因为有GIL锁的存在,在Cpython中,没有真正的线程并行。但是有多进程并行

     当任务是计算密集的情况下使用多进程。

  (5) 守护线程和守护进程的区别

     守护进程:要么自己正常结束,要么等主进程的代码结束。

     守护线程:要么自己正常结束,要么要等主进程的进程结束。

四、线程的使用方法。

  (1)锁机制

      递归锁  Rlock()  可以有无数的锁,但是这些锁有一把万能钥匙。

    

from threading import Thread, RLock def fn(r_tot, r_pap): r_tot.acquire() print('我在厕所') r_pap.acquire() print('我还有纸') r_tot.release() r_pap.release() def fn1(r_pap, r_tot): r_pap.acquire() print('wo也有纸') r_tot.acquire() print('我想上厕所') r_pap.release() r_tot.release() r_tot = r_pap = RLock() t1 = Thread(target=fn, args=(r_tot, r_pap)) t2 = Thread(target=fn1, args=(r_pap, r_tot)) t1.start() t2.start() 线程中的递归锁(Rlock)

 

 

 

    

 

      互斥锁  Lock()  一把锁配一把钥匙

      GIL:全局解释锁  锁的是线程,同一时间只允许一个线程访问cpu

  (2)信号量

      from threading import Semaphore

      

from threading import Thread, Semaphore import time def fn(s, i, color): s.acquire() print('%s%s个小浣熊出生了\033[0m' % (color, i)) time.sleep(1) s.release() def fn1(s, i, color): s.acquire() print('%s%s个大灰狼来吃小浣熊了\033[0m' % (color, i)) s.release() s = Semaphore(5) for i in range(10): t1 = Thread(target=fn, args=(s, (i + 1), '\033[35m')) t2 = Thread(target=fn1, args=(s, (i + 1), '\033[36m')) t1.start() t2.start() 线程中的信号量(Semaphore)

 

 

 

      

 

  (3)事件

    from threading import Event

    

from threading import Thread,Event import time,random def conn_mysql(e,i): count = 1 while count <= 3: if e.is_set(): print('第%s个人连接成功!'%i) break print('正在尝试第%s次重新连接...'%(count)) e.wait(0.5) count += 1 def check_mysql(e): print('\033[42m 数据库正在维护 \033[0m') time.sleep(random.randint(1,2)) e.set() if __name__ == '__main__': e = Event() t_check = Thread(target=check_mysql,args=(e,)) t_check.start() for i in range(10): t_conn = Thread(target=conn_mysql,args=(e,i)) t_conn.start() 线程事件机制(Event)

 

 

 

  (4)条件

    from threading import Condition

    条件是让程序员自行去调度线程的一个机制

    Condition 有四个方法

    acquire()

    release()

    wait()  是让线程阻塞

    notify(int)  是指给wait发一个信号,让wait 变成 不阻塞

          int 是指,要给多少个wait 发信号

    

from threading import Thread,Condition def func(con,i): con.acquire() con.wait()# 线程执行到这里,会阻塞住,等待notify发送信号,来唤醒此线程 con.release() print('第%s个线程开始执行了!'%i) if __name__ == '__main__': con = Condition() for i in range(10): t = Thread(target=func,args=(con,i)) t.start() while 1: num = int(input(">>>")) con.acquire() con.notify(num)# 发送一个信号给num个正在阻塞在wait的线程,让这些线程正常执行 con.release() 使用条件去调度线程

 

 

  (5)定时器

    from threading import Timer

    Timer(time, func)

    time:表示睡眠的时间,以秒为单位

    func:睡眠之后需要执行的任务。

    

from threading import Timer def fn(): print('我要执行了') print(type(te)) te = Timer(2, fn) # 等待2秒,然后执行fn。 te.start() 定时器(Timer)

五、线程池

    from concurrent.futures import ThreadPoolExector

    concurrent.futures  这个模块是异步调用的机制

    提交任务的方法有两种:

      t = ThreadPoolExector

      1.  t.submit(func,参数)

      2.  t.map(func,可迭代对象)

    在进程池中用 apply_async() 时,主进程要写close 和 join

    在线程池中 要写shutdown 作用相当于进程池中的 close + join        

    不同的提交任务的方式获取值的方法也不同。

      t.submit()提交,需要用result()来获取

      

 

      t.map() 提交,需要用__next__来获取

      

 

from concurrent.futures import ThreadPoolExecutor def fn(num): sum = 0 for i in range(num): sum += i print(sum) t = ThreadPoolExecutor() for i in range(10) t.submit(fn,i) t.shutdown() 线程池(concurrent.frutures) from concurrent.futures import ThreadPoolExecutor def fn(i): num = 0 for el in range(i): num += el print(num) t = ThreadPoolExecutor(5) t.map(fn, range(10)) t.shutdown() map实现线程池

    线程池中的回调函数

    线程中的回调函数是由子线程调用的

    

 

from concurrent.futures import ThreadPoolExecutor import time import threading def fn1(num): time.sleep(2) print('子线程', threading.current_thread()) return num def fn2(sta): time.sleep(2) print('回调函数', threading.current_thread()) t = ThreadPoolExecutor() print('主线程', threading.current_thread()) time.sleep(2) for i in range(2): t.submit(fn1, i).add_done_callback(fn2) t.shutdown() 回调函数被谁调用的代码

 

 

from concurrent.futures import ThreadPoolExecutor def fn1(num): sum = 0 for i in range(num): sum += i return sum def fn2(sta): print(sta.result()) t = ThreadPoolExecutor() for i in range(10): t.submit(fn1, i).add_done_callback(fn2) t.shutdown() 线程中的回调函数

 

  

转载于:https://www.cnblogs.com/wf123/p/9525730.html

相关资源:老生常谈进程线程协程那些事儿

最新回复(0)