python
threading
多线程
一. Threading简介
首先看下面的没有用Threading的程序
import threading,time
def fun():
s = 0
for i in range(30):
s += i
time.sleep(0.1)
print(s)
if __name__ == '__main__':
t = time.time()
fun()
fun()
print(time.time()-t)
>>>
435
435
6.023701906204224
[Finished in 6.6s]
如果使用线程会有什么样的效果呢
import threading,time
def fun():
s = 0
for i in range(30):
s += i
time.sleep(0.1)
print(s)
if __name__ == '__main__':
# 创建了一个线程列表,包含2个线程
ths = [threading.Thread(target=fun) for i in range(2)]
for th in ths:
th.start()
t = time.time()
for th in ths:
th.join()
print(time.time()-t)
>>>
435
435
3.116874933242798
[Finished in 3.7s]
这说明两个线程几乎是同时进行的
二. Threading的应用进阶
import threading,time
class MyThread(threading.Thread):
def run(self):
for i in range(30):
print('threading:',i)
time.sleep(0.1)
if __name__ == '__main__':
t = MyThread()
t.start()
t.join(1)
for i in range(10):
print('Main:',i)
time.sleep(0.1)
>>>
threading: 0
threading: 1
threading: 2
主线程等待t这个线程0.1秒后也开始运行
Main: 0
threading: 3
Main: 1
threading: 4
Main: 2
threading: 5
Main: 3
threading: 6
Main: 4
threading: 7
Main: 5
threading: 8
Main: 6
threading: 9
Main: 7
Main: 8
Main: 9
[Finished in 2.0s]
注意每次运行的结果都不太一样
2)daemon属性 被设定为后台运行的线程,会在主程序退出时主动自杀。 设置为后台运行线程的方法是:设置线程的daemon属性为True
import threading,time
def dmn():
print('dmn start...')
time.sleep(2)
print('dmn end.')
def ndmn():
print('ndmn start...')
time.sleep(1)
print('ndmn end.')
d = threading.Thread(target=dmn)
d.daemon = True
n = threading.Thread(target=ndmn)
print('start...')
d.start()
n.start()
print('end.')
>>>
start...
dmn start...
ndmn start...
end.
ndmn end.
[Finished in 1.3s]
由上面打印的结果我们可以看到dmn线程设置为后台线程后,它的 print('dmn end.') 语句并不没有执行,这是因为后台线程在主线程结束后会自杀,所以主线程执行完后,dmn线程没能说出自己的“遗言”。 作为对比,我将daemon设为False,结果如下
...
d = threading.Thread(target=dmn)
d.daemon = False
...
>>>
start...
dmn start...
ndmn start...
end.
ndmn end.
dmn end.
[Finished in 2.5s]
线程同步
1 )指令锁 threading.Lock
acquire尝试获得锁定,进入阻塞状态。 acquire(blocking=True, timeout=-1))
release释放获得锁定(资源使用完后) release()
import threading,time,random
share = 4
lock = threading.Lock() #初始化指令锁
class MyThread(threading.Thread):
def __init__(self,i):
super().__init__()
self.i = i
def run(self):
global share
for d in range(2):
lock.acquire()
print(share)
share += self.i
time.sleep(random.random())
print('+',self.i,'=',share)
lock.release()
if __name__ == '__main__':
t = MyThread(2)
tt = MyThread(6)
t.start()
tt.start()
>>>
4
+ 2 = 6
6
+ 6 = 12
12
+ 2 = 14
14
+ 6 = 20
[Finished in 2.9s]
为了更好的感受指令锁的作用,将acquire和release去掉后结果如下
...
def run(self):
global share
for d in range(2):
# lock.acquire()
print(share)
share += self.i
time.sleep(random.random())
print('+',self.i,'=',share)
# lock.release()
...
>>>
4
6
+ 6 = 12
12
+ 2 = 18
18
+ 6 = 20
+ 2 = 20
[Finished in 2.2s]
比较后可以知道,加了指令锁后可以清楚地知道对共享资源share操作的具体情况
2 )条件变量threading.Condition 属性
实现严格的依照次序操作的线程之间的通信。 典型的实例:生产者/消费者(只有生产后,才能消费)。 线程之间可以互相通知,以达到默契的配合。 条件变量可以使用默认的锁或用户创建的锁来工作。
话不多说看代码
import threading,time
share = 0
share_cond = threading.Condition()
# 生产者
class ProThread(threading.Thread):
def __init__(self):
super().__init__()
self.name = 'Produce'
def run(self):
global share
if share_cond.acquire():
while True:
if not share: # 若没东西了,即开始生产
share += 1
print(self.name,share)
share_cond.notify() #唤醒消费者?这个是我自己的理解
share_cond.wait()
time.sleep(1)
# 消费者
class CustomThread(threading.Thread):
def __init__(self):
super().__init__()
self.name = 'Custom'
def run(self):
global share
if share_cond.acquire():
while True:
if share:
share -= 1 # 若有东西就买买买
print(self.name,share)
share_cond.notify() #唤醒生产者,同上,仅是个人理解,如有错请告知,谢谢
share_cond.wait()
time.sleep(1)
if __name__ == '__main__':
t = ProThread()
tt = CustomThread()
t.start()
tt.start()
>>>
Produce 1
Custom 0
Produce 1
Custom 0
Produce 1
Custom 0
...
...
...
上面的结果会一直重复执行下去
3 ) 信号量threading.Semaphore
属性
import threading,time
sema = threading.Semaphore(2)
class MyThread(threading.Thread):
def __init__(self,name):
super().__init__()
self.name = name
def run(self):
if sema.acquire():
print(self.name,'Had got resource.')
time.sleep(1)
sema.release()
print(self.name,'Had released resource.')
if __name__ == '__main__':
ths = [MyThread(str(i)+'Sema') for i in range(5)]
for th in ths:
th.start()
>>>
0Sema Had got resource.
1Sema Had got resource.
2Sema Had got resource.
1Sema Had released resource.
3Sema Had got resource.
0Sema Had released resource.
3Sema Had released resource.
4Sema Had got resource.
2Sema Had released resource.
4Sema Had released resource.
[Finished in 3.6s]
4 ) 线程通信threading.Event
import threading,time
event = threading.Event()
class MyThreadWait(threading.Thread):
def run(self):
self.name = 'Wait Thread'
print(self.name,"Wait...")
event.wait()
print(self.name,"Start...")
event.clear()
class MyThreadMain(threading.Thread):
def run(self):
time.sleep(3)
print('Main thread set event flag!')
event.set()
if __name__ == '__main__':
thw = MyThreadWait()
thm = MyThreadMain()
thw.start()
thm.start()
>>>
Wait Thread Wait...
Main thread set event flag!
Wait Thread Start...
[Finished in 3.6s]
好了,大概就是这些了,其他的以后再补充,另外感谢麦子学院提供的免费课程~~~真心不是打广告