• threading 学习笔记


    一、线程基础

    1、线程状态 

    2、线程互斥锁同步控制 

    多个线程需要修改同一共享数据时,需要进行同步控制,引入了锁的概念。

     

    a、同一时间可能有多个线程在锁定池中,它们处于同步阻塞状态竞争锁定;

    b、同一时间只能有一个线程获得锁定处于运行状态。 

    3、条件变量(线程通信) 

    有的线程需要预备条件才能干活。
    

    二、threading:线程创建、启动、睡眠、退出

    1、方法一:将要执行的函数作为参数传递给 threading.Thread() 

     1 # -*- coding:utf-8 -*- 
     2 import threading, time
     3 def func(n): 
     4     global count
     5     time.sleep(0.1)
     6     for i in range(n):
     7         count += 1
     8 if __name__==’__main__’: 
     9     count = 0
    10     threads = []
    11     for i in range(5):
    12          threads.append(threading.Thread(target=func, args=(1000,)))
    13     for t in threads:
    14          t.start() 
    15     time.sleep(5)
    16     print(‘count:’,count)                    

    以上例子创建了 5 个线程去执行 func 函数。获得的结果可能是 5000,但也有时候会出现错误,解决方法请继续阅 读下文。
    要点:

    1. threading.Thread(target=func, args=(10,)):func 为函数名,args 为函数参数(必须以元组的形式传递 );

    2. t.start(): 启动函数,等待操作系统调度;

    c. 函数运行结束,线程也就结束;
    d. time.sleep(): 线程进入睡眠,处于 IO 阻塞状态。

    1、方法二:继承 threading.Thread()类,并重写 run()

     1 # -*- coding:utf-8 -*- 
     2 import threading, time
     3 class myThread(threading.Thread): 
     4     def __init__(self, n):
     5           threading.Thread.__init__(self)
     6           self.myThread_n = n 
     7     def run(self):
     8           global count
     9           for i in range(self.myThread_n):
    10                 count += 1
    11 if __name__==’__main__’: 
    12         count = 0
    13         threads = []
    14         for i in range(5):
    15                 threads.append(myThread(1000))
    16         for t in threads:
    17                 t.start() 
    18         time.sleep(5)
    19         print(‘count:’,count)   

    要点:
    a. threading.Thread.__init__(self):回调父类方法。如果你重写了__init__()方法,这一步是必须的,否则出错。 

    三、threading:线程同步锁互斥控制

    因为线程是乱序执行的,在某种情况下上面的两个例子,输出的结果可能不是预期的值。

    我将第 2 例的线程类修改下,让问题更加突出,然后你每次运行的时候再把线程数也修改下,

    并计算出预期结果和运行 结果对比。一定要多试几次哦。 

    1 class myThread(threading.Thread): 
    2     def __init__(self, n):
    3         threading.Thread.__init__(self)
    4         self.myThread_n = n 
    5     def run(self):
    6         global count
    7         for i in range(self.myThread_n):
    8               __Temp = count time.sleep(0.0001)
    9               count = __Temp + 1        

    是不是输出的结果和预期结果不一致啊,呵呵!因为多个线程都在同时操作同一个共享资源

    ,所以造成资源破坏。不过 我们可以通过同步锁来解决这种问题: 

     1 # -*- coding:utf-8 -*-
     2 import threading, time
     3 class myThread(threading.Thread): 
     4     def __init__(self, n):
     5         threading.Thread.__init__(self)
     6         self.myThread_n = n 
     7     def run(self):
     8         global count
     9         for i in range(self.myThread_n):
    10             if lock.acquire():
    11                  __Temp = count
    12                 time.sleep(0.0001) 
    13                 count = __Temp + 1 
    14                 lock.release()
    15 if __name__==’__main__’: 
    16     count = 0
    17     lock = threading.Lock() #同步锁
    18     threads = []
    19     for i in range(5):
    20       
    21         threads.append(myThread(1000)) for t in threads:
    22     t.start() time.sleep(5)
    23     print(‘count:’,count)            

    要点:

    1. lock = threading.Lock():创建锁;

    2. lock.acquire([timeount]):请求锁定,如果设定了 timeout,则在超时后通过返回值可以判断是否得到了锁 , 

          从而可以进行一些其他的处理 ; c. lock.release():释放锁定。 

    四、threading:线程死锁和递归锁

    1、死锁

    a. 在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,

    就会造成死锁 , 因为系统判断这部分资源都正在使用 ,所有这两个线程在无外力作用下将一直

    等待下去 。下面是一个死锁的例 子: 

     1 # -*- coding:utf-8 -*- 
     2 import threading, time
     3 class myThread(threading.Thread):
     4      def doA(self):
     5             if lockA.acquire(): 
     6                   print(self.name,”got lockA.”) time.sleep(0.0001)
     7             if lockB.acquire():
     8                   print(self.name,”got lockB”)
     9                   lockB.release()
    10             lockA.release()
    11     def doB(self):
    12             if lockB.acquire():
    13                    print(self.name,”got lockB.”) 
    14                    time.sleep(0.0001)
    15                    if lockA.acquire():
    16                          print(self.name,”got lockA”)
    17                          lockA.release()
    18                    lockB.release()
    19      def run(self): 
    20             self.doA() 
    21             self.doB()
    22 if __name__==’__main__’: 
    23       lockA = threading.Lock() 
    24       lockB = threading.Lock()
    25       threads = []
    26       for i in range(5):
    27              threads.append(myThread()) 
    28       for t in threads:
    29            t.start()
    30       for t in threads:
    31            t.join() #等待线程结束,后面再讲。    

    b. 当一个线程已经获得了锁,再此请求锁也会出现死锁,请看下面的例子: 

     1 # -*- coding:utf-8 -*- 
     2 import threading, time 
     3 import random
     4 class myThread(threading.Thread): 
     5     def toHex(self):
     6         global L
     7         if lock.acquire(1):
     8             for i in range(len(L)):
     9                 if type(L[i]) is int: L[i]=”{:X}”.format(L[i])
    10             lock.release() 
    11         else:
    12             print(self.name,“错误,系统忙”) 
    13     def run(self):
    14         global L
    15         if lock.acquire(1):
    16             L.append(random.randint(0, 15)) 
    17             self.toHex()
    18             lock.release()
    19         else: 
    20             print(self.name,“错误,系统忙”)
    21 if __name__==’__main__’: 
    22         L = []
    23         lock = threading.Lock()
    24         threads = []
    25         for i in range(5):
    26             threads.append(myThread()) 
    27         for t in threads:
    28                 t.start()
    29         for t in threads:
    30                 t.join() #等待线程结束,后面再讲。            

    2、递归锁(也称可重入锁)

        上一例子的死锁,我们可以用递归锁解决:
     1 #lock = threading.Lock() 注释掉此行,并加入下行。 2 lock = threading.RLock() 

    为了支持在同一线程中多次请求同一资源 ,python 提供了“可重入锁”:threading.RLock。RLock 内部维护着一个 Lock 和一个 counter 变量,counter 记录了 acquire 的次数,从而使得资源可以被多次 require。直到一个线程所有的 acquire 都 被 release,其他的线程才能获得资源。

        递归锁一般应用于复杂的逻辑。
    

    五、threading:条件变量同步

    有一类线程需要满足条件之后才能够继续执行, Python 提供了 threading.Condition 对象用于条件变量线程的支持,它除 了能提供 RLock()或 Lock()的方法外,还提供了 wait()、notify()、notifyAll()方法。

    lock_con = threading.Condition([Lock/Rlock]) :锁是可选选项,不传人锁,对象自动创建一个 RLock()。 wait():条件不满足时调用,线程会释放锁并进入等待阻塞; notify():条件创造后调用,通知等待池激活一个线程;

    #lock = threading.Lock() 注释掉此行,并加入下行。 lock = threading.RLock()

    notifyAll():条件创造后调用,通知等待池激活所有线程。 

     
  • 相关阅读:
    android 之 ListView相关
    android 之 菜单
    android 之 Dialog
    android 之 View
    android 之 service
    android 之 Intent、broadcast
    Service Broadcast简单音乐播放功能
    剑指offer面试题43:n个筛子的点数
    C# LINQ语法
    C# Linq
  • 原文地址:https://www.cnblogs.com/lixiaomingpython/p/6820900.html
Copyright © 2020-2023  润新知