thread
目录
import threading
import time
简单的创建
def run(n):
print("task", n)
1)
time.sleep(print('2s')
1)
time.sleep(print('1s')
1)
time.sleep(print('0s')
1)
time.sleep(
if __name__ == '__main__':
= threading.Thread(target=run, args=("t1",))
t1 = threading.Thread(target=run, args=("t2",))
t2
t1.start() t2.start()
通过类创建
class MyThread(threading.Thread):
def __init__(self, n):
super(MyThread, self).__init__() # 重构run函数必须要写
self.n = n
def run(self):
print("task", self.n)
1)
time.sleep(print('2s')
1)
time.sleep(print('1s')
1)
time.sleep(print('0s')
1)
time.sleep(
if __name__ == "__main__":
= MyThread("t1")
t1 = MyThread("t2")
t2
t1.start() t2.start()
对比没有join()和join()的区别
def run(n):
print("task", n)
1) #此时子线程停1s
time.sleep(print('3')
1)
time.sleep(print('2')
1)
time.sleep(print('1')
if __name__ == '__main__':
= threading.Thread(target=run, args=("t1",))
t True) #把子进程设置为守护线程,必须在start()之前设置
t.setDaemon(
t.start()print("end")
def run(n):
print("task", n)
1) #此时子线程停1s
time.sleep(print('3')
1)
time.sleep(print('2')
1)
time.sleep(print('1')
if __name__ == '__main__':
= threading.Thread(target=run, args=("t1",))
t True) #把子进程设置为守护线程,必须在start()之前设置
t.setDaemon(
t.start()# 设置主线程等待子线程结束
t.join() print("end")
锁的应用
def run(n, semaphore):
#加锁
semaphore.acquire() 1)
time.sleep(print("run the thread:%s\n" % n)
#释放
semaphore.release()
if __name__ == '__main__':
= 0
num = threading.BoundedSemaphore(5) # 最多允许5个线程同时运行
semaphore for i in range(22):
= threading.Thread(target=run, args=("t-%s" % i, semaphore))
t
t.start()while threading.active_count() != 1:
pass # print threading.active_count()
else:
print('--')
事件类
= threading.Event()
event
def lighter():
= 0
count set() #初始值为绿灯
event.while True:
if 5 < count <=10 :
# 红灯,清除标志位
event.clear() print("\33[41;1mred light is on...\033[0m")
elif count > 10:
set() # 绿灯,设置标志位
event.= 0
count else:
print("\33[42;1mgreen light is on...\033[0m")
1)
time.sleep(+= 1
count
def car(name):
while True:
if event.is_set(): #判断是否设置了标志位(绿灯)
print("[%s] running..."%name)
1)
time.sleep(else:
print("[%s] sees red light,waiting..."%name)
#如果变为绿灯
event.wait()print("[%s] green light is on,start going..."%name)
= threading.Thread(target=lighter,)
light
light.start()
= threading.Thread(target=car,args=("MINI",))
car car.start()
queue队列
import threading
import queue,time
=queue.Queue(maxsize=10)
qdef Producer(name):
=1
countwhile True:
"骨头 %s"%count)
q.put(print("{}生产了骨头".format(name),count)
+=1
count1)
time.sleep(def Consumer(name):
while True:
print("[%s] 取到 [%s] 并且吃了它。。。"%(name,q.get()))
1)
time.sleep(=threading.Thread(target=Producer,args=('wlb',))
p=threading.Thread(target=Consumer,args=("dog",))
c=threading.Thread(target=Consumer,args=("cat",))
c1
p.start()
c.start() c1.start()
互斥锁
由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,当多个线程同时修改同一条数据时可能会出现脏数据,所以,出现了线程锁,即同一时刻允许一个线程执行操作。线程锁用于锁定资源,你可以定义多个锁, 像下面的代码, 当你需要独占某一资源时,任何一个锁都可以锁这个资源,就好比你用不同的锁都可以把相同的一个门锁住是一个道理。
由于线程之间是进行随机调度,如果有多个线程同时操作一个对象,如果没有很好地保护该对象,会造成程序结果的不可预期,我们也称此为“线程不安全”。
为了方式上面情况的发生,就出现了互斥锁(Lock)
from threading import Thread,Lock
import os,time
def work():
global n
lock.acquire()=n
temp0.1)
time.sleep(=temp-1
n
lock.release()if __name__ == '__main__':
=Lock()
lock=100
n=[]
lfor i in range(100):
=Thread(target=work)
p
l.append(p)
p.start()for p in l:
p.join()
信号量
互斥锁同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去。
import threading
import time
def run(n, semaphore):
#加锁
semaphore.acquire() 1)
time.sleep(print("run the thread:%s\n" % n)
#释放
semaphore.release()
if __name__ == '__main__':
= 0
num = threading.BoundedSemaphore(5) # 最多允许5个线程同时运行
semaphore for i in range(22):
= threading.Thread(target=run, args=("t-%s" % i, semaphore))
t
t.start()while threading.active_count() != 1:
pass # print threading.active_count()
else:
print('--')
GIL(Global Interpreter Lock)全局解释器锁
在非python环境中,单核情况下,同时只能有一个任务执行。多核时可以支持多个线程同时执行。但是在python中,无论有多少核,同时只能执行一个线程。究其原因,这就是由于GIL的存在导致的。
GIL的全称是Global Interpreter Lock(全局解释器锁),来源是python设计之初的考虑,为了数据安全所做的决定。某个线程想要执行,必须先拿到GIL,我们可以把GIL看作是“通行证”,并且在一个python进程中,GIL只有一个。拿不到通行证的线程,就不允许进入CPU执行。GIL只在cpython中才有,因为cpython调用的是c语言的原生线程,所以他不能直接操作cpu,只能利用GIL保证同一时间只能有一个线程拿到数据。而在pypy和jpython中是没有GIL的。
Python多线程的工作过程: python在使用多线程的时候,调用的是c语言的原生线程。
- 拿到公共数据
- 申请gil
- python解释器调用os原生线程
- os操作cpu执行运算
- 当该线程执行时间到后,无论运算是否已经执行完,gil都被要求释放 进而由其他进程重复上面的过程
- 等其他进程执行完后,又会切换到之前的线程(从他记录的上下文继续执行),整个过程是每个线程执行自己的运算,当执行时间到就进行切换(context switch)。