
*****
## 多任務
有很多的場景中的事情是同時進行的,比如開車的時候 手和腳共同來駕駛汽車,再比如唱歌跳舞也是同時進行的
### 程序中模擬多任務
~~~
import time
def sing():
for i in range(3):
print("正在唱歌...%d"%i)
time.sleep(1)
def dance():
for i in range(3):
print("正在跳舞...%d"%i)
time.sleep(1)
if __name__ == '__main__':
sing()
dance()
~~~
### 多任務的理解

- 并行:真的多任務 cpu大于當前執行的任務
- 并發:假的多任務 cpu小于當前執行的任務
### 線程完成多任務
~~~
import threading
import time
def demo():
# 子線程
print("hello girls")
time.sleep(1)
if __name__ == "__main__":
for i in range(5):
t = threading.Thread(target=demo)
t.start()
~~~
### 查看線程數量
```
threading.enumerate() 查看當前線程的數量
```
### 驗證子線程的執行與創建
當調用Thread的時候,不會創建線程。
當調用Thread創建出來的實例對象的start方法的時候,才會創建線程以及開始運行這個線程。
### 繼承Thread類創建線程
~~~
import threading
import time
class A(threading.Thread):
def __init__(self,name):
super().__init__(name=name)
def run(self):
for i in range(5):
print(i)
if __name__ == "__main__":
t = A('test_name')
t.start()
~~~
### 多線程共享全局變量(線程間通信)
修改全局變量一定需要加global嘛?
<br>在一個函數中,對全局變量進行修改的時候,是否要加global要看是否對全局變量的指向進行了修改,如果修改了指向,那么必須使用global,僅僅是修改了指向的空間中的數據,此時不用必須使用global
### 多線程參數-args
~~~
threading.Thread(target=test, args=(num,))
~~~
### 共享全局變量資源競爭
一個線程寫入,一個線程讀取,沒問題,如果兩個線程都寫入呢?
### 互斥鎖
當多個線程幾乎同時修改某一個共享數據的時候,需要進行同步控制
<br>某個線程要更改共享數據時,先將其鎖定,此時資源的狀態為"鎖定",其他線程不能改變,只到該線程釋放資源,將資源的狀態變成"非鎖定",其他的線程才能再次鎖定該資源。互斥鎖保證了每次只有一個線程進行寫入操作,從而保證了多線程情況下數據的正確性。
~~~
創建鎖
mutex = threading.Lock()
鎖定
mutex.acquire()
解鎖
mutex.release()
~~~
### 死鎖
在線程間共享多個資源的時候,如果兩個線程分別占有一部分資源并且同時等待對方的資源,就會造成死鎖。
~~~
import threading
import time
class MyThread1(threading.Thread):
def run(self):
# 對mutexA上鎖
mutexA.acquire()
# mutexA上鎖后,延時1秒,等待另外那個線程 把mutexB上鎖
print(self.name+'----do1---up----')
time.sleep(1)
# 此時會堵塞,因為這個mutexB已經被另外的線程搶先上鎖了
mutexB.acquire()
print(self.name+'----do1---down----')
mutexB.release()
# 對mutexA解鎖
mutexA.release()
class MyThread2(threading.Thread):
def run(self):
# 對mutexB上鎖
mutexB.acquire()
# mutexB上鎖后,延時1秒,等待另外那個線程 把mutexA上鎖
print(self.name+'----do2---up----')
time.sleep(1)
# 此時會堵塞,因為這個mutexA已經被另外的線程搶先上鎖了
mutexA.acquire()
print(self.name+'----do2---down----')
mutexA.release()
# 對mutexB解鎖
mutexB.release()
mutexA = threading.Lock()
mutexB = threading.Lock()
if __name__ == '__main__':
t1 = MyThread1()
t2 = MyThread2()
t1.start()
t2.start()
~~~
### 避免死鎖
- 程序設計時要盡量避免
- 添加超時時間等
### 線程同步
天貓精靈:小愛同學
小愛同學:在
天貓精靈:現在幾點了?
小愛同學:你猜猜現在幾點了
### 多任務版udp聊天
1 創建套接字
2 綁定本地信息
3 獲取對方IP和端口
4 發送、接收數據
5 創建兩個線程,去執行功能