线程相关的其他方法
Thread实例对象的方法
# isAlive(): 返回线程是否活动的。
# getName(): 返回线程名。
# setName(): 设置线程名。
threading模块提供的一些方法:
# threading.currentThread(): 返回当前的线程变量。
# threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
# threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
from threading import Thread, current_thread,active_count
import os
import time
def func(name, i):
print('%s running'%name)
print('子线程current_thread:',current_thread().name)
print('子线程getpid:', os.getpid())
time.sleep(i)
print('over')
t1 = Thread(target=func, args=('waller', 1))
t2 = Thread(target=func, args=('waller', 2))
t1.start()
t2.start()
# t1.join() # 主线程等到子线程t1运行结束后再运行
print('当前活跃线程数:',active_count())
print('主')
join
主线程等待子线程结束
from threading import Thread
import time
def sayhi(name):
time.sleep(2)
print('%s say hello' %name)
if __name__ == '__main__':
t=Thread(target=sayhi,args=('xxx',))
t.start()
t.join()
print('主线程')
print(t.is_alive())
'''
egon say hello
主线程
False
'''
守护线程 t.daemo = True
无论是进程还是线程,都遵循:守护xxx会等待主xxx运行完毕后被销毁
需要强调的是:运行完毕并非终止运行
1.对主进程来说,运行完毕指的是主进程代码运行完毕
2.对主线程来说,运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕
主线程必须等待其他非守护线程的结束才能结束
(因为子线程在运行的时候需要使用进程中的资源,而主线程一旦结束资源也就消除了)
详解:
#1 主进程在其代码结束后就已经算运行完毕了(守护进程在此时就被回收),然后主进程会一直等非守护的子进程都运行完毕后回收子进程的资源(否则会产生僵尸进程),才会结束,
#2 主线程在其他非守护线程运行完毕后才算运行完毕(守护线程在此时就被回收)。因为主线程的结束意味着进程的结束,进程整体的资源都将被回收,而进程必须保证非守护线程都运行完毕后才能结束。
from threading import Thread, current_thread
import time
def func(i):
print(current_thread().name)
time.sleep(i)
print('over')
t = Thread(target=func, args=(1,))
t.daemon = True
t.start()
print('主')
'''
Thread-1
主
'''
线程互斥锁
多个线程操作同一个数据也会出现数据混乱现象 需要上锁
from threading import Thread, Lock
import time
x = 5
def num(mutex):
global x
mutex.acquire()
number = x
time.sleep(1)
x = number - 1
mutex.release()
l = []
mutex = Lock()
for i in range(5):
t = Thread(target=num, args=(mutex,))
t.start()
l.append(t)
for t in l:
t.join() # 主线程等待每个子线程运行结束后再运行
print(x)
print(l)
# [<Thread(Thread-1, stopped 25852)>, <Thread(Thread-2, stopped 26124)>,
# <Thread(Thread-3, stopped 7944)>, <Thread(Thread-4, stopped 17120)>,
# <Thread(Thread-5, stopped 19236)>]
复制代码
信号量Semaphore
同进程的一样
Semaphore管理一个内置的计数器,
每当调用acquire()时内置计数器-1;
调用release() 时内置计数器+1;
计数器不能小于0;当计数器为0时,acquire()将阻塞线程直到其他线程调用release()。
实例:(同时只有5个线程可以获得semaphore,即可以限制最大连接数为5):
from threading import Thread, Semaphore
import time
import random
sem = Semaphore(5) # 生成一把锁五把钥匙
def func(name):
sem.acquire()
print('%s进门了'%name)
time.sleep(random.randint(1, 3))
sem.release()
print('%s出门了'%name)
for i in range(10):
t = Thread(target=func, args=(i, ))
t.start()
线程间通信
线程间的数据是共享的
from threading import Thread
# 线程之间数据时共享的
x = 100
def num():
global x
x = 666
t = Thread(target=num)
t.start()
print(x) # >>> 666
同一个进程下的多个线程本来就是数据共享,为什么还要用队列?
因为队列是 管道+锁,使用队列就不需要自己动手操作锁的问题
import queue
q = queue.Queue()
q.put('one')
q.put('two')
q.put('three')
print(q.get()) # >>> one 先进先出
q = queue.LifoQueue()
q.put('one')
q.put('two')
q.put('three')
print(q.get()) # >>> three 堆栈 先进后出
q = queue.PriorityQueue() # 数字越小,优先级越高
q.put((10, 'one'))
q.put((1, 'two'))
q.put((5, 'three'))
print(q.get()) # >>> (1, 'two')
Event事件
一个线程要等到另一个线程运行到某一时刻再运行
event.isSet():返回event的状态值;
event.wait():如果 event.isSet()==False将阻塞线程;
event.set(): 设置event的状态值为True,所有阻塞池的线程激活进入就绪状态, 等待操作系统调度;
event.clear():恢复event的状态值为False。
from threading import Thread, Event
import time
e = Event()
def light():
print('红灯')
time.sleep(3)
e.set()
print('绿灯')
def car(name):
print('%s等红灯'%name)
e.wait()
print('%s开车了'%name)
t = Thread(target=light)
t.start()
for i in range(10):
t = Thread(target=car, args=('车手%i'%i, ))
t.start()