python多线程
并发和并行
并发:是指在一个时间段内发生若干事件的情况。系统具备处理多个任务(动作)的能力。
并行:是指在统一是同一时刻发生若干事件的情况 。系统具备同时处理多个任务(动作)的能力。
同步和异步
同步:就是并发或者并行的各个任务不是独立运行的,任务之间有一定的交替顺序,可能一个任务运行结束,另一个任务才开始,好比是接力跑,拿到接力棒才可以跑。
异步:就是并发或者并行的各个任务是独立运行的,任务之间不受影响,任务之间好比各个选手在是在不同的赛道上比赛。
threading模块提供了Thread类来处理线程包括:
run() : 用以表示线程活动的方法。
start() : 启动线程活动。
join([timeout]) :等待至线程终止。阻塞线程直到线程的join()方法被调用为止或到达指定的timeout(可选参数)。
isAlive() : 返回线程是否是活动的。
getName() : 返回线程名。
setName() :设置线程名。
import time def countdown(n,name): while n >0: print('Hi',n,name) n-=1 time.sleep(2) from threading import Thread list_t = [] for i in range(4): t = Thread(target=countdown,args=(10,i)) t.start() list_t.append(t) for j in list_t: j.join() print('main is over')
1.启动和停止线程
#将要执行的方法作为参数传给Thread的构造方法
import time def countdown(n): while n >0: print('Hi',n) n-=1 time.sleep(2) from threading import Thread t = Thread(target=countdown,args=(10,)) t.start()#调用 start() 方法时,它会调用你传递进来的函数,并把你传递进来的参数传递给该函数
#从Thread继承,并重写run()
import time from threading import Thread class MyThread(Thread): def __init__(self,arg): super(MyThread,self).__init__() self.arg =arg def run(self): while self.arg>0: print('Hi',self.arg) self.arg -=1 time.sleep(2) t= MyThread(10) t.start()
如果你需要终止线程,那么这个线程必须通过编程在某个特定点轮询来退出。
from threading import Thread import time class Countdown: def __init__(self): self._running = True def terminate(self): self._running = False def run(self,n): while self._running and n > 0: print('Hi',n) n-=1 time.sleep(2) c=Countdown() t= Thread(target=c.run,args=(10,)) t.start() c.terminate()
如果线程执行一些像 I/O 这样的阻塞操作,那么通过轮询来终止线程将使得线程 之间的协调变得非常棘手。比如,如果一个线程一直阻塞在一个 I/O 操作上,它就永远无法返回,也就无法检查自己是否已经被结束了。要正确处理这些问题,你需要利用超时循环来小心操作线程
2.线程锁。
线程来说,最大的特点就是线程之间可以共享数据,共享数据就会出现多线程同时更改一个变量,使用同样的资源,而出现死锁、数据错乱等情况。
Lock(指令锁)是可用的最低级的同步指令,
RLock(可重入锁)是一个可以被同一个线程请求多次的同步指令
acquire([timeout]): 尝试获得锁定。使线程进入同步阻塞状态。
release(): 释放锁。使用前线程必须已获得锁定,否则将抛出异常。
import threading import time gl_num = 0 lock = threading.RLock() def Func(): lock.acquire()#调用acquire([timeout])时,线程将一直阻塞,直到获得锁定或者直到timeout秒后(timeout参数可选) global gl_num gl_num += 1 time.sleep(1) print (gl_num) lock.release() for i in range(10): t = threading.Thread(target=Func) t.start()
3.线程的一个关键特性是每个线程都是独立运行且状态不可预测。如果程序中的其他线程需要通过判断某个线程的状态来确定自己下一步的操作,这时线程同步问题就会变得非常棘手。为了解决这些问题,我们需要使用 threading 库中的 Event 对象。
Event内置了一个初始为False的标志,当调用set()时设为True,调用clear()时重置为 False。wait()将阻塞线程至等待阻塞状态
from threading import Thread, Event import time def countdown(n, started_evt): print('countdown starting') started_evt.set() while n > 0: print('T-minus', n) n -= 1 time.sleep(5) started_evt = Event() print('Launching countdown') t = Thread(target=countdown, args=(10,started_evt)) t.start() started_evt.wait() print('countdown is running')
4.Timer(定时器)是Thread的派生类,用于在指定的时间后调用一个方法
Timer(interval, function, args=[], kwargs={})
interval: 指定的时间
function: 要执行的方法
args/kwargs: 方法的参数
import threading def func(): '''do something''' timer = threading.Timer(5, func) timer.start()
5.condition()如果一个线程需要不停地重复使用 event 对象,最好使用 Condition 对象来代替。Condiftion理解为一把高级的琐,它提供了比Lock, RLock更高级的功能,允许我们能够控制复杂的线程同步问题。
acquire([timeout])/release(): 调用关联的锁的相应方法。
wait([timeout]): 调用这个方法将使线程进入Condition的等待池等待通知,并释放锁。使用前线程必须已获得锁定,否则将抛出异常。
notify(): 调用这个方法将从等待池挑选一个线程并通知,收到通知的线程将自动调用acquire()尝试获得锁定(进入锁定池);其他线程仍然在等待池中。调用这个方法不会释放锁定。使用前线程必须已获得锁定,否则将抛出异常。
notifyAll(): 调用这个方法将通知等待池中所有的线程,这些线程都将进入锁定池尝试获得锁定。调用这个方法不会释放锁定。使用前线程必须已获得锁定,否则将抛出异常。
import threading, time
class Seeker(threading.Thread):
def __init__(self, cond, name):
super(Seeker, self).__init__()
self.cond = cond
self.name = name
def run(self):
print(self.name + ': 我已经把眼睛蒙上了')
time.sleep(1) # 确保先运行Hider中的方法
self.cond.acquire()
self.cond.notify()
self.cond.wait()
print(self.name + ': 我找到你了 ~_~')
self.cond.notify()
self.cond.release()
print(self.name + ': 我赢了')
class Hider(threading.Thread):
def __init__(self, cond, name):
super(Hider, self).__init__()
self.cond = cond
self.name = name
def run(self):
self.cond.acquire()
self.cond.wait() #释放对琐的占用,同时线程挂起在这里,直到被notify并重新占有琐。
print(self.name + ': 我已经藏好了,你快来找我吧')
self.cond.notify()
self.cond.wait()
self.cond.release()
print(self.name + ': 被你找到了,哎~~~')
cond = threading.Condition()
seeker = Seeker(cond, 'seeker')
hider = Hider(cond, 'hider')
seeker.start()
hider.start()