#常规写法
import threading import time def sayhi(num): # 定义每一个线程要运行的函数 print("running on number:%s" % num) time.sleep(3) if __name__ == '__main__': t1 = threading.Thread(target=sayhi, args=(1,)) # 生成一个线程实例 t2 = threading.Thread(target=sayhi, args=(2,)) # 生成另外一个线程实例 t1.start() # 启动线程 t2.start() # 启动另外一个线程 print(t1.getName()) # 获取线程名 print(t2.getName())
自定义线程类 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()
import threading import time def sayhi(num): # 定义每一个线程要运行的函数 print("running on number:%s" % num) time.sleep(3) start_time=time.time() if __name__ == '__main__': for i in range(50): ###多线程 t = threading.Thread(target=sayhi, args=(i,)) # 生成一个线程实例 t.start() print (start_time-time.time()) ####打印时间 此时打印结果时间为0.0000几秒,是由于程序在执行完多线程时继续往下执行,而不会等待线程执行完在打印时间,因此打印出来的时间并非多线程执行的时间
join() 线程执行后,主线程会等待全部线程执行完毕后继续往下走,下面实例介绍计算多线程执行时间 import threading import time def sayhi(num): # 定义每一个线程要运行的函数 print("running on number:%s" % num) time.sleep(3) start_time=time.time() threads = [] ####定义一个列表,将全部的线程加进去 if __name__ == '__main__': for i in range(50): ###多线程 t = threading.Thread(target=sayhi, args=(i,)) # 生成一个线程实例 t.start() threads.append(t) ####将每一个线程添加到列表 for t in threads: ###循环整个列表,进行join(每一个线程join完成后主线程才会继续往下走) t.join() ###等待全部线程执行结束,至关于单线程 print (start_time-time.time())
示例二python
#!/usr/bin/env python #-*-coding:utf-8-*- import threading from time import ctime,sleep import time def music(func): for i in range(2): print ("Begin listening to %s. %s" %(func,ctime())) sleep(1) print("end listening %s"%ctime()) def move(func): for i in range(2): print ("Begin watching at the %s! %s" %(func,ctime())) sleep(5) print('end watching %s'%ctime()) threads = [] t1 = threading.Thread(target=music,args=('music',)) threads.append(t1) t2 = threading.Thread(target=move,args=('movie',)) threads.append(t2) if __name__ == '__main__': for t in threads: t.start() print ("all over %s" %ctime())
主线程不会等待守护线程结束在退出,会等待非守护线程执行完毕才退出多线程
将线程设置为Daemon线程,它作为程序主线程的守护线程,当主线程退出时,线程也会退出,由守护线程动的其它子线程会同时退出,不论是否执行完任务并发
因为线程之间是进行随机调度,而且每一个线程可能只执行n条执行以后,当多个线程同时修改同一条数据时可能会出现脏数据,因此,出现了线程锁 - 即同一时刻容许一个线程执行操做app
###没有加锁时 import threading import time,sys def addNum(): global num # 在每一个线程中都获取这个全局变量 print('--get num:', num) time.sleep(1) num -= 1 # 对此公共变量进行-1操做 num = 100 # 设定一个共享变量 thread_list = [] for i in range(100): t = threading.Thread(target=addNum) t.start() thread_list.append(t) for t in thread_list: # 等待全部线程执行完毕 t.join() print('final num:', num) 说明: 正常来说,这个num结果应该是0, 但在python 2.7上多运行几回,会发现,最后打印出来的num结果不老是0,为何每次运行的结果不同呢?
假设你有A,B两个线程,此时都 要对num 进行减1操做, 因为2个线程是并发同时运行的,因此2个线程颇有可能同时拿走了num=100这个初始变量交给cpu去运算,当A线程去处完的结果是99,但此时B线程运算完的结果也是99,两个线程同时CPU运算的结果再赋值给num变量后,结果就都是99。那怎么办呢? 很简单,每一个线程在要修改公共数据时,为了不本身在还没改完的时候别人也来修改此数据,能够给这个数据加一把锁, 这样其它线程想修改此数据时就必须等待你修改完毕并把锁释放掉后才能再访问此数据。 加锁版本: import threading import time gl_num = 0 lock = threading.RLock() ## 生成全局锁 def Func(): lock.acquire() #修改数据前加锁 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()
递归锁(即大锁之下在加小锁)dom
import threading, time
def run1():
print("grab the first part data")
lock.acquire()
global num
num += 1
lock.release()
return num
def run2():
print("grab the second part data")
lock.acquire()
global num2
num2 += 1
lock.release()
return num2
def run3():
lock.acquire()
res = run1()
print('--------between run1 and run2-----')
res2 = run2()
lock.release()
print(res, res2)
if __name__ == '__main__':
num, num2 = 0, 0
lock = threading.RLock() for i in range(10): t = threading.Thread(target=run3) t.start() while threading.active_count() != 1: print(threading.active_count())
else:
print('----all threads done---')
print(num, num2)
有一类线程须要知足条件以后才可以继续执行,Python提供了threading.Condition 对象用于条件变量线程的支持,它除了能提供RLock()或Lock()的方法外,还提供了 wait()、notify()、notifyAll()方法。ide
lock_con=threading.Condition([Lock/Rlock]): 锁是可选选项,不传人锁,对象自动建立一个RLock()。
wait():条件不知足时调用,线程会释放锁并进入等待阻塞; notify():条件创造后调用,通知等待池激活一个线程; notifyAll():条件创造后调用,通知等待池激活全部线程。
示例函数
import threading,time from random import randint class Producer(threading.Thread): def run(self): global L while True: val=randint(0,100) print('生产者',self.name,":Append"+str(val),L) if lock_con.acquire(): L.append(val) lock_con.notify() lock_con.release() time.sleep(3) class Consumer(threading.Thread): def run(self): global L while True: lock_con.acquire() if len(L)==0: lock_con.wait() print('消费者',self.name,":Delete"+str(L[0]),L) del L[0] lock_con.release() time.sleep(0.25) if __name__=="__main__": L=[] lock_con=threading.Condition() threads=[] for i in range(5): threads.append(Producer()) threads.append(Consumer()) for t in threads: t.start() for t in threads: t.join()
互斥锁,同时只容许一个线程更改数据,而Semaphore是同时容许必定数量的线程更改数据 ,好比两个水龙头,那最多只容许2我的同时使用,后面的人只能等有人用完后才能使用。ui
信号量用来控制线程并发数的,BoundedSemaphore或Semaphore管理一个内置的计数 器,每当调用acquire()时-1,调用release()时+1。spa
计数器不能小于0,当计数器为 0时,acquire()将阻塞线程至同步锁定状态,直到其余线程调用release()。(相似于停车位的概念)线程
BoundedSemaphore与Semaphore的惟一区别在于前者将在调用release()时检查计数 器的值是否超过了计数器的初始值,若是超过了将抛出一个异常。
实例:
import threading, time def run(n): semaphore.acquire() time.sleep(1) print("run the thread: %s" % n) semaphore.release() if __name__ == '__main__': num = 0 semaphore = threading.BoundedSemaphore(5) # 最多容许5个线程同时运行,有一个执行完毕后会执行另外一个 for i in range(20): t = threading.Thread(target=run, args=(i,)) t.start()