线程模块threading

线程 -Threading模块 -使用和进程基本相似

  • 多线程中是可以input

  • 在使用的过程中从用户层面上并没有感觉到和进程的差别,但是有本质差别

  • 执行代码的最小单元

  • 每一个进程至少有一个线程,这个线程是主线程

  • 一个进程内的所有线程之间的数据是共享的

      #启动多线程
      from threading import Thread
      import time
      
      def func(i):
          time.sleep(1)
          print(i)
      
      for i in range(10):
          t = Thread(target=func, args=(i,))
          t.start()
      print('这是主线程执行的')
      #结果
      这是主线程执行的
      0
      2
      1
      3
      4
      5
      9
      8
      6
      7	#这里的十个数字是几乎同时被输出,说明是个线程并发
    
  • 面向对象的形式启动线程

      #用面向对象的方法开启新的线程
      from threading import Thread
      class MyThread(Thread): #继承Thread类
          def __init__(self, arg): #重写__init__方法,用于给这个类传参
              super().__init__()  #继承父类的__init__方法
              self.arg = arg  #将自己的参数赋给对象
      
          def run(self):  		        
          '''objece.start()直接调用这个方法'''
              self.methond()
      
          def methond(self):
              '''这个类中的其他方法'''
              print(self.arg)	
    

进程|主线程|子线程

  • 进程是最小的内存分配单位
  • 线程是操作系统调度的最小单位
  • 线程被cpu执行了
  • 进程中可以有多个线层,至少一个主线程
  • 主线程
  • 子线程
    • 子线程的数据储存在栈中
  • 全局变量global n线程共享

线程锁 -这是解释语言的一个不可避免的问题

  • 全局解释器锁 -锁的是线程
    • 同一时刻只能有一个线程访问cpu

进程和线程的效率对比 -线程快

from multiprocessing import Process
from threading import Thread
import time

def cal_num(i):
    i += 1

if __name__ == '__main__':
    p_list = []
    start = time.time()
    for i in range(100):    #创建100个进程执行计算
        p = Process(target=cal_num, args=(i, ))
        p.start()
        p_list.append(p)
    for i in p_list:
        i.join()
    end = time.time()
    t1 = end - start


start = time.time()
t_list = []
for i in range(100):
    t = Thread(target=cal_num, args=(i,))
    t.start()
    t_list.append(t)
for i in t_list:
    i.join()
end = time.time()
t2 = end - start
print('100个进程消耗时间{} \n 100个线程消耗时间{}'.format(t1, t2))
#结果
100个进程消耗时间0.19627618789672852  
100个线程消耗时间0.009418964385986328

线程中的其他方法 -threading.方法名()

  • threading.current_thread() 所有进程的情况
  • .get_ident() 查看进程的id
  • .active_count() 查看活跃进程的数量
  • .enumerate() 所有的进程情况放进一个列表中

守护线程 -守护线程和进程的区别

  • 将子线程设置成守护线程,守护线程将在主线程代码执行结束且其他线程执行结束后结束
  • 但是守护进程是在主进程结束之后结束,不等待其他子进程是否结束

线程锁 -Lock()和RLock

科学家吃面模型 -死锁模型

  • Lock()的死锁现象
  • Lock()互斥锁,只有一把钥匙
  • RLock()递归锁,只要拿到一把,就等于拿到一串,必须等一串全部归还下个线程才能继续拿钥匙
    • 死锁情况

        #死锁情况
        from threading import Thread,Lock	
        from time import sleep
        #死锁情况
        from threading import Thread,Lock,RLock
        from time import sleep
        
        mt_lock = Lock()
        cz_lock = Lock()
        def miantao():
            mt_lock.acquire()
            print('拿到面条了')
            sleep(1)
            cz_lock.acquire()
            print('拿到叉子了')
            print('吃面')
            mt_lock.release()
            cz_lock.release()
        
        def chazi():
            cz_lock.acquire()
            print('拿到叉子了')
            sleep(1)
            mt_lock.acquire()
            print('拿到面条了')
            print('吃面')
            cz_lock.release()
            mt_lock.release()
        
        th1 = Thread(target=miantao, args=())
        th2 = Thread(target=chazi, args=())
        th1.start()
        th2.start()
      
    • 解决死锁问题RLock()

        from threading import Thread, Lock, RLock
        from time import sleep
        
        cz_lock = mt_lock = RLock()	#这里创建递归锁
        def miantao():
            mt_lock.acquire()
            print('拿到面条了')
            sleep(1)
            cz_lock.acquire()
            print('拿到叉子了')
            print('吃面')
            mt_lock.release()
            cz_lock.release()
        
        def chazi():
            cz_lock.acquire()
            print('拿到叉子了')
            sleep(1)
            mt_lock.acquire()
            print('拿到面条了')
            print('吃面')
            cz_lock.release()
            mt_lock.release()	
        
        th1 = Thread(target=miantao, args=())
        th2 = Thread(target=chazi, args=())
        th1.start()
        th2.start()
      

信号量 -同进程

  • 限制一段代码有且只有n个线程同时调用

事件 -同进程

  • 创建就为阻塞状态

实例 -链接数据库,以及数据库的可连接的情况

	from threading import Thread, Event

	e = Event()
	def test():
	    '''检测数据库的连通性'''
	    info = input('>>')
	    if info == '1':
	        e.set()
	        print('数据库网络连接打开')
	    else:
	        print('关闭数据库网络连接')
	def connect_q():
	    '''连接数据库'''
	    print('等待数据库网络连接')
	    e.wait()
	    print('数据库连接成功!') 	
	
	t1 = Thread(target=test)
	t2 = Thread(target=connect_q)
	t1.start()
	t2.start() 

条件 -Condition

  • .acquire() #钥匙

  • .release() #释放钥匙

  • .notify(num) #允许钥匙串有几把钥匙

  • .wait() #等待.notify(num)提供钥匙数量

      #条件
      from threading import Condition, Thread
    
      def print_thrad(con, i):
          con.acquire()	#这里也有锁
          con.wait()
          print('第{}线程运行了'.format(i)) 
          con.release()
      
      num = int(input('>>'))
      con = Condition()
      
      
      for i in range(10):
          t = Thread(target=print_thrad, args=(con, i))
          t.start()
      
      con.acquire()	#这里也有锁
      con.notify(num) #前后必须有钥匙和锁
      con.release()
    

定时器 -Timer()

  • 定时开启一个线程

  • 用法和Threa()一致

      from threading import Timer
    
      def func():
          print('两秒时间到了')
      Timer(2, func).start()
      print('呵呵')
      #结果
      呵呵
      两秒时间到了	#子线程两秒后才开启
    

线程队列 -queue.Queue()

  • .put() 放元素
  • .put_nowait() #放元素,没有元素报错
  • .get() #取出元素
  • .get_nowait() #没有元素报错

其他队列模块中的类

先进后出 LifoQueue()

优先级队列 PriorityQueue()

posted @ 2018-10-04 15:55  小白的蟒蛇  阅读(88)  评论(0编辑  收藏  举报