老男孩旗下品牌:网校平台

老男孩IT教育,只培养技术精英

全国免费咨询电话:400-609-2893
Python学习必备知识:Python线程那些事

    /    2017-07-13

Python是每一个源码语言爱好者都必须学习的一个过程,今天小编就Python线程一些知识点跟大家简单的分析一下。 一、线程创建 1 #方法一:将要执行的方法作为参数传给Thread的构造方法 2 import threading 3 import time 4 5 def show(arg): 6     time.sleep(2) 7     print('thread' + str(arg)) 8 9 for i in range(10): 10     t = threading.Thread(target=show,args=(i,)) 11     time.sleep(2) 12     t.start() 13 14 #方法2:从Thread继承,并重写run() 15 class MyThread(threading.Thread): 16     def __init__(self,num): 17         threading.Thread.__init__(self) 18         self.num = num 19 20     def run(self)):#定义每个线程要运行的函数 21         print("running on number:%s" %self.num) 22         time.sleep(3) 23 24 25 if __name__ ==  '__main__': 26     t1 = MyThread(1) 27     t2 = MyThread(2) 28     t1.start() 29     time.sleep(3) 30     t2.start() 注解: Thread(group=None,target=None,name=None,args=(),kwargs={}) group:线程组,目前还没有实现,库引用时提示必须是None target:要执行的方法 name:线程名 args/kwargs:要传入方法的参数,args和kwargs两个参数其实是二选一 #实例方法 isAlive():返回线程是否在运行 get/setName(name):获取/设置线程名 is/setDaemon(bool):获取/设置是否守护线程。初始值从创建该线程的线程继承,当没有非守护线程仍在运行时,程序将终止 start():启动线程 join([timeout]):阻塞当前上下文环境的线程。 二、Python多线程用法 1 import threading 2 from time import ctime,sleep 3 4 def music(func): 5     for i in range(2): 6         print("I was listening to %s. %s" %(func,ctime())) 7         sleep(1) 8 def move(func): 9     for i in range(2): 10         print("I was at the %s! %s" %(func,ctime())) 11         sleep(5) 12 13 threads = [] 14 t1 = threading.Thread(target=music,args=('童话镇',)) 15 threads.append(t1) 16 t2 = threading.Thread(target=move,args=('变形金刚',)) 17 threads.append(t2) 18 19 if __name__ == '__main__': 20     for t in threads: 21         t.setDaemon(True) 22         t.start() 23 24     print("all over %s" %ctime()) 注: threads = [] t1 = threading.Thread(target=music,args=('童话镇',)) threads.append(t1)   创建了threads数组,创建线程t1,使用threading.Thread()方法,在这个方法中调用music方法target=music,args方法对music进行传参。 把创建好的线程t1装到threads数组中。   接着以同样的方式创建线程t2,并把t2也装到threads数组。 for t in threads:   t.setDaemon(True)   t.start() 最后通过for循环遍历数组。(数组被装载了t1和t2两个线程) setDaemon()   setDaemon(True)将线程声明为守护线程,必须在start() 方法调用之前设置,如果不设置为守护线程程序会被无限挂起。子线程启动后,父线程也继续执行下去,当父线程执行完最后一条语句print "all over %s" %ctime()后,没有等待子线程,直接就退出了,同时子线程也一同结束。       serDeamon(False)(默认)前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,主线程停止。 运行结果: 1 2 3     I was listening to 童话镇. Thu Jun 22 23:23:07 2017 I was at the 变形金刚! Thu Jun 22 23:23:07 2017 all over Thu Jun 22 23:23:07 2017         从执行结果来看,子线程(muisc 、move )和主线程(print "all over %s" %ctime())都是同一时间启动,但由于主线程执行完结束,所以导致子线程也终止。 调整程序: 复制代码 1 if __name__ == '__main__': 2     for t in threads: 3         t.setDaemon(True) 4         t.start() 5     6     t.join() 7 8     print "all over %s" %ctime() 复制代码         加了join()方法,用于等待线程终止。join()的作用是,在子线程完成运行之前,这个子线程的父线程将一直被阻塞。         join()方法的位置是在for循环外的,也就是说必须等待for循环里的两个进程都结束后,才去执行主进程。 运行结果: 1 ############运行结果################### 2 I was listening to 童话镇. Thu Jun 22 23:34:22 2017 3 I was at the 变形金刚! Thu Jun 22 23:34:22 2017 4 I was listening to 童话镇. Thu Jun 22 23:34:23 2017 5 I was at the 变形金刚! Thu Jun 22 23:34:27 2017 6 all over Thu Jun 22 23:34:32 2017 从结果的时间可以看出每首歌之间等待1秒,电影之间等待5秒,但是是同步进行的,总的时间为5秒 三、线程锁(LOCK,RLOCK)         由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,当多个线程同时修改同一条数据时可能会出现脏数据,所以,出现了线程锁 - 同一时刻允许一个线程执行操作。   Lock(指令锁)是可用的最低级的同步指令。Lock处于锁定状态时,不被特定的线程拥有。Lock包含两种状态——锁定和非锁定,以及两个基本的方法。   可以认为Lock有一个锁定池,当线程请求锁定时,将线程至于池中,直到获得锁定后出池。池中的线程处于状态图中的同步阻塞状态。     RLock(可重入锁)是一个可以被同一个线程请求多次的同步指令。RLock使用了“拥有的线程”和“递归等级”的概念,处于锁定状态时,RLock被某个线程拥有。拥有RLock的线程可以再次调用acquire(),释放锁时需要调用release()相同次数。   可以认为RLock包含一个锁定池和一个初始值为0的计数器,每次成功调用 acquire()/release(),计数器将+1/-1,为0时锁处于未锁定状态。   简言之:Lock属于全局,Rlock属于线程。 1,未使用锁 1 import threading 2 import time 3 4 num = 0 5 6 def show(arg): 7     global num 8     time.sleep(1) 9     num +=1 10     print(num) 11 12 for i in range(10): 13     t = threading.Thread(target=show, args=(i,)) 14     t.start() 15 16 print('main thread stop') 多次运行可能产生混乱。这种场景就是适合使用锁的场景。 2.使用锁 复制代码 1 import threading 2 import time 3 4 num = 0 5 lock = threading.RLock() 6 7 # 调用acquire([timeout])时,线程将一直阻塞, 8 # 直到获得锁定或者直到timeout秒后(timeout参数可选)。 9 # 返回是否获得锁。 10 def show(arg): 11     lock.acquire() 12     global num 13     time.sleep(1) 14     num +=1 15     print(num) 16     lock.release() 17 18 for i in range(10): 19     t = threading.Thread(target=show, args=(i,)) 20     t.start() 21 22 print('main thread stop') 加上锁后数字会一步步打印出来,不会因为拥堵而错乱的情况! 四、信号量(Semaphore) 互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去。 1 import threading, time 2 3 def run(n): 4     semaphore.acquire() 5     time.sleep(3) 6     print("run the thread: %s" % n) 7     semaphore.release() 8 9 if __name__ == '__main__': 10     num = 0 11     semaphore = threading.BoundedSemaphore(5)  # 最多允许5个线程同时运行 12     for i in range(20): 13         t = threading.Thread(target=run, args=(i,)) 14         t.start() 五、事件(event) Python线程的事件主要用于主线程控制其他线程的执行,事件主要提供了三个方法:set、wait、clear 事件处理的机制:全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,那么event.wait 方法时便不再阻塞。 clear:将“Flag”设置为False set:将“Flag”设置为True 用threading.Event实现线程间的通讯 threading.Event使一个线程等待其他线程的通知,把这个Event传递到线程对象中,Event默认内置了一个标志,初始值为False。 一旦该线程通过wait()方法进入等待状态,直到另一个线程调用该Event的set()方法将内置标志设置为True时, 该Event会通知所有等待状态的线程恢复运行。 复制代码 1 import threading 2 3 def do(event): 4     print('start') 5     event.wait() 6     print('end') 7 8 event_obj = threading.Event() 9 10 for i in range(10): 11     t = threading.Thread(target=do, args=(event_obj,)) 12     t.start() 13 14 event_obj.clear() #继续阻塞 15 16 inp = input('input:') 17 if inp == 'true': 18     event_obj.set()  # 唤醒 六、条件(condition) 所谓条件变量,即这种机制是在满足特定条件之后,线程才可以访问相关的数据! 它使用Condition类来完成,由于它也可以像锁机制那样用,所以它也有acquire方法和release方法,而且它还有wait,notify,notifyAll方法 一个简单的生产消费者模型,通过条件变量的控制产品数量的增减,调用一次生产者产品就是+1,调用一次消费者产品就会-1. 使用 Condition 类来完成,由于它也可以像锁机制那样用,所以它也有 acquire 方法和 release 方法,而且它还有 wait, notify, notifyAll 方法。 复制代码 1 import threading 2 import  time 3 4 # 产品类 5 class Goods: 6     def __init__(self): 7         self.count = 0 8 9     def add(self, num=1): 10         self.count += num 11 12     def sub(self): 13         if self.count >= 0: 14             self.count -= 1 15 16     def empty(self): 17         return self.count <= 0="" 18="" 19="" 20="" 21="" 22="" 23="" 24="" 25="" 26="" 27="" 28="" 29="" 30="" 31="" 32="" 33="" 34="" 35="" class="" :="" def="" sleeptime="1):" self.cond="condition" self.goods="goods" self.sleeptime="sleeptime" cond="self.cond" goods="self.goods" while="" true:="" -=""> 其实就是唤醒消费者进程 36             cond.notifyAll() 37             # 解锁资源 38             cond.release() 39             time.sleep(self.sleeptime) 40 41 42 # 消费者 43 class Consumer(threading.Thread): 44     def __init__(self, condition, goods, sleeptime=2): 45         threading.Thread.__init__(self) 46         self.cond = condition 47         self.goods = goods 48         self.sleeptime = sleeptime 49 50     def run(self): 51         cond = self.cond 52         goods = self.goods 53 54         while True: 55             time.sleep(self.sleeptime) 56             # 锁住资源 57             cond.acquire() 58             # 如无产品则让线程等待 59             while goods.empty(): 60                 cond.wait() 61             goods.sub() 62             print("产品数量:", goods.count, "消费者线程") 63             64 65 g = Goods() 66 c = threading.Condition() 67 pro = Producer(c, g) 68 pro.start() 69 con = Consumer(c, g) 70 con.start() 七、定时器(Timer) 1 import threading 2 def SayHello(): 3     print("hello world!") 4     t=threading.Timer(3,SayHello) 5     t.start() 6 def other_func(): 7     print("let me running!") 8     t=threading.Timer(1,other_func) 9     t.start() 10 11 if __name__ == "__main__": 12     SayHello() 13     other_func()

(0)

分享至