Python线程

Posted linrui

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python线程相关的知识,希望对你有一定的参考价值。

Python线程

Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元。

threading模块对象

  描述
Thread 表示一个线程的执行的对象
Lock 锁原语对象
RLock 可重入锁对象。使单线程可以再次获得已经获得了的锁(递归锁定)
Event 通用的条件变量。多个线程可以等待某个事件的发生,在事件发生后,所有的线程都会被激活
BoundedSemaphore 每次允许几个线程通过
Timer 等待多久在开始运行

 

 

 

 

 

 

 

 1 import threading
 2 import time
 3   
 4 def sayhi(num): #定义每个线程要运行的函数
 5     print("running on number:%s" %num)
 6     time.sleep(3)
 7   
 8 if __name__ == __main__:
 9     t1 = threading.Thread(target=sayhi,args=(1,)) #生成一个线程实例
10     t2 = threading.Thread(target=sayhi,args=(2,)) #生成另一个线程实例
11     t1.start() #启动线程
12     t2.start() #启动另一个线程
13 
14     print(t1.getName()) #获取线程名
15     print(t2.getName())

线程的方法:

    • start              线程准备就绪,等待CPU调度
    • setName       为线程设置名称
    • getName       获取线程名称
    • setDaemon   设置为后台线程或前台线程(默认)
                            如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止
                            如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止
    • join                逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得无意义
    • run                线程被cpu调度后自动执行线程对象的run方法

继承式调用

技术分享图片
import threading
import time


class MyThread(threading.Thread):
    def __init__(self,num):
        threading.Thread.__init__(self)
        self.num = num

    def run(self):#定义每个线程要运行的函数
        print("running on number:%s" %self.num)
        time.sleep(3)
  
if __name__ == __main__:
    t1 = MyThread(1)
    t2 = MyThread(2)
    t1.start()
    t2.start()
View Code

 

线程锁(Lock、RLock)

由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,当多个线程同时修改同一条数据时可能会出现脏数据,所以,出现了线程锁 - 同一时刻允许一个线程执行操作。

请求锁定 — 进入锁定池等待 — 获取锁 — 已锁定 — 释放锁 
Lock(指令锁)是可用的最低级的同步指令。Lock处于锁定状态时,不被特定的线程拥有。Lock包含两种状态——锁定和非锁定,以及两个基本的方法。 
可以认为Lock有一个锁定池,当线程请求锁定时,将线程至于池中,直到获得锁定后出池。池中的线程处于状态图中的同步阻塞状态。 
构造方法: 
Lock() 
实例方法: 
acquire([timeout]): 使线程进入同步阻塞状态,尝试获得锁定。 
release(): 释放锁。使用前线程必须已获得锁定,否则将抛出异常。

 

技术分享图片
 1 import time
 2 import threading
 3 
 4 def addNum():
 5     global num #在每个线程中都获取这个全局变量
 6     print(--get num:,num )
 7     time.sleep(1)
 8     lock.acquire() #修改数据前加锁
 9     num  -=1 #对此公共变量进行-1操作
10     lock.release() #修改后释放
11 
12 num = 100  #设定一个共享变量
13 thread_list = []
14 lock = threading.Lock() #生成全局锁
15 for i in range(100):
16     t = threading.Thread(target=addNum)
17     t.start()
18     thread_list.append(t)
19 
20 for t in thread_list: #等待所有线程执行完毕
21     t.join()
22 
23 print(final num:, num )
View Code

 

RLock(递归锁)

RLock(可重入锁)是一个可以被同一个线程请求多次的同步指令。RLock使用了“拥有的线程”和“递归等级”的概念,处于锁定状态时,RLock被某个线程拥有。拥有RLock的线程可以再次调用acquire(),释放锁时需要调用release()相同次数。 
可以认为RLock包含一个锁定池和一个初始值为0的计数器,每次成功调用 acquire()/release(),计数器将+1/-1,为0时锁处于未锁定状态。 
构造方法: 
RLock()

说白了就是在一个大锁中还要再包含子锁

 

技术分享图片
 1 import threading,time
 2   
 3 def run1():
 4     print("grab the first part data")
 5     lock.acquire()
 6     global num
 7     num +=1
 8     lock.release()
 9     return num
10 def run2():
11     print("grab the second part data")
12     lock.acquire()
13     global  num2
14     num2+=1
15     lock.release()
16     return num2
17 def run3():
18     lock.acquire()
19     res = run1()
20     print(--------between run1 and run2-----)
21     res2 = run2()
22     lock.release()
23     print(res,res2)
24   
25   
26 if __name__ == __main__:
27   
28     num,num2 = 0,0
29     lock = threading.RLock()
30     for i in range(10):
31         t = threading.Thread(target=run3)
32         t.start()
33   
34 while threading.active_count() != 1:
35     print(threading.active_count())
36 else:
37     print(----all threads done---)
38     print(num,num2)
View Code

信号量(Semaphore)

互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 。

 

技术分享图片
 1 import threading,time
 2   
 3 def run(n):
 4     semaphore.acquire()
 5     time.sleep(1)
 6     print("run the thread: %s
" %n)
 7     semaphore.release()
 8   
 9 if __name__ == __main__:
10   
11     num= 0
12     semaphore  = threading.BoundedSemaphore(5) #最多允许5个线程同时运行
13     for i in range(20):
14         t = threading.Thread(target=run,args=(i,))
15         t.start()
16   
17 while threading.active_count() != 1:
18     pass #print threading.active_count()
19 else:
20     print(----all threads done---)
21     print(num)
View Code

 

事件(event)

python线程的事件用于主线程控制其他线程的执行,事件主要提供了三个方法 set、wait、clear。

Event内部包含了一个标志位,初始的时候为false。 
可以使用set()来将其设置为true; 
或者使用clear()将其从新设置为false; 
可以使用is_set()来检查标志位的状态; 
另一个最重要的函数就是wait(timeout=None),用来阻塞当前线程,直到event的内部标志位被设置为true或者timeout超时。如果内部标志位为true则wait()函数理解返回。

事件处理的机制:全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,那么event.wait 方法时便不再阻塞。

  • clear:将“Flag”设置为False
  • set:将“Flag”设置为True

 通过Event来实现两个或多个线程间的交互,下面是一个红绿灯的例子,即起动一个线程做交通指挥灯,生成几个线程做车辆,车辆行驶按红灯停,绿灯行的规则。

 

技术分享图片
 1 import threading,time
 2 import random
 3 def light():
 4     if not event.isSet():
 5         event.set() #wait就不阻塞 #绿灯状态
 6     count = 0
 7     while True:
 8         if count < 10:
 9             print(33[42;1m--green light on---33[0m)
10         elif count <13:
11             print(33[43;1m--yellow light on---33[0m)
12         elif count <20:
13             if event.isSet():
14                 event.clear()
15             print(33[41;1m--red light on---33[0m)
16         else:
17             count = 0
18             event.set() #打开绿灯
19         time.sleep(1)
20         count +=1
21 def car(n):
22     while 1:
23         time.sleep(random.randrange(10))
24         if  event.isSet(): #绿灯
25             print("car [%s] is running.." % n)
26         else:
27             print("car [%s] is waiting for the red light.." %n)
28 if __name__ == __main__:
29     event = threading.Event()
30     Light = threading.Thread(target=light)
31     Light.start()
32     for i in range(3):
33         t = threading.Thread(target=car,args=(i,))
34         t.start()
View Code

 

条件(Condition)

  可以把Condition理解为一把高级的琐,它提供了比Lock, RLock更高级的功能,允许我们能够控制复杂的线程同步问题。threadiong.Condition在内部维护一个琐对象(默认是RLock),可以在创建Condigtion对象的时候把琐对象作为参数传入。Condition也提供了acquire, release方法,其含义与琐的acquire, release方法一致,其实它只是简单的调用内部琐对象的对应的方法而已。Condition还提供了如下方法(特别要注意:这些方法只有在占用琐(acquire)之后才能调用,否则将会报RuntimeError异常。):

Condition.wait([timeout]): 
wait方法释放内部所占用的琐,同时线程被挂起,直至接收到通知被唤醒或超时(如果提供了timeout参数的话)。当线程被唤醒并重新占有琐的时候,程序才会继续执行下去。

Condition.notify(): 
唤醒一个挂起的线程(如果存在挂起的线程)。注意:notify()方法不会释放所占用的琐。

Condition.notify_all() 
Condition.notifyAll() 
唤醒所有挂起的线程(如果存在挂起的线程)。注意:这些方法不会释放所占用的琐。

使得线程等待,只有满足某条件时,才释放n个线程

 

技术分享图片
 1 import threading
 2   
 3 def run(n):
 4     con.acquire()
 5     con.wait()
 6     print("run the thread: %s" %n)
 7     con.release()
 8   
 9 if __name__ == __main__:
10   
11     con = threading.Condition()
12     for i in range(10):
13         t = threading.Thread(target=run, args=(i,))
14         t.start()
15   
16     while True:
17         inp = input(>>>)
18         if inp == q:
19             break
20         con.acquire()
21         con.notify(int(inp))
22         con.release()
23         def condition_func():
24             ret = False
25             inp = input(>>>)
26             if inp == 1:
27                 ret = True
28                 return ret
29         def run(n):
30             con.acquire()
31             con.wait_for(condition_func)
32             print("run the thread: %s" %n)
33             con.release()
34 if __name__ == __main__:
35     con = threading.Condition()
36     for i in range(10):
37         t = threading.Thread(target=run, args=(i,))
38         t.start()
View Code

 

Timer

定时器,指定n秒后执行某操作

技术分享图片
1 def hello():
2     print("hello, world")
3   
4 t = Timer(30.0, hello)
5 t.start()  # after 30 seconds, "hello, world" will be printed
View Code

 





















以上是关于Python线程的主要内容,如果未能解决你的问题,请参考以下文章

python threading超线程使用简单范例的代码

[Python3] 043 多线程 简介

newCacheThreadPool()newFixedThreadPool()newScheduledThreadPool()newSingleThreadExecutor()自定义线程池(代码片段

python中的多线程和多进程编程

常用python日期日志获取内容循环的代码片段

多线程 Thread 线程同步 synchronized