python網絡線程

線程

線程是一種多任務編程的方式,可使用計算機多核資源。線程又被稱爲輕量級的進程java

線程特徵python

  * 線程是計算機核心分配的最小單位
  * 一個進程能夠包含多個線程
  * 線程也是一個運行過程,也要消耗計算機資源。多個線程共享其進程的資源和空間
  * 線程也擁有本身特有的資源屬性,好比指令集,TID等
  * 線程不管建立仍是刪除仍是運行資源消耗都小於進程
  * 多個線程之間並行執行,互不干擾編程

threading線程模塊

from threading import Threadc#

t = Thread(target, [, args], [kwargs])安全

建立線程對象多線程

  • target 綁定線程函數
  • args 元組 給線程函數位置傳參
  • kwargs 字典 給線程函數鍵值傳參

t.start()        啓動線程併發

t.join([timeout])   回收線程app

import threading
import os

a = 1

# 線程函數
def music():
  print("進程pid號", os.getpid())
  global a
  print("a = ",a)
  a = 10000

t = threading.Thread(target=music)    # 建立線程對象
t.start()                               # 啓動線程

print("進程pid號", os.getpid())

t.join()                                # 回收線程

print("Main a:",a)

# 進程pid號 12549
# 進程pid號 12549
# a =  1
# Main a: 10000

 os.getpid獲取的是進程的pid號,線程是進程中的一個成員.ide

線程中改的變量,是進程中的變量.並無新開闢一個空間.函數

線程屬性

t.is_alive()  查看線程狀態

t.name  線程名稱  默認Thread-1

t.setName()  設置線程名稱

threading.currentThread()  獲取當前線程對象

 1 from threading import Thread,currentThread
 2 from time import sleep 
 3 
 4 #線程函數
 5 def fun(sec):
 6     print("線程屬性測試")
 7     sleep(sec)
 8     #獲取線程對象 getName()獲取名字
 9     print("%s 線程結束"%currentThread().getName())
10 
11 thread = []
12 
13 for i in range(3):
14     t = Thread(target = fun,name = "tedu%d"%i,\
15         args = (3,))
16     thread.append(t)
17     t.start()
18     print(t.is_alive())  #查看進程狀態
19 
20 thread[1].setName('Tarena')  #設置線程名稱
21 print(thread[2].name) #獲取線程名稱
22 
23 #回收線程
24 for i in thread:
25     i.join()
26 
27 # 線程屬性測試
28 # True
29 # 線程屬性測試
30 # True
31 # 線程屬性測試
32 # True
33 # tedu2
34 # Tarena 線程結束
35 # tedu0 線程結束
36 # tedu2 線程結束
View Code

t.daemon

默認狀況下,主線程的結束不會影響分支線程,若是設置爲True則主線程退出分支線程也會退出

設置方法:

t.daemon = True

t.setDaemon()

線程daemon屬性的設置在start前;通常設置daemon後不會使用join

from threading import Thread
from time import sleep

def fun():
  sleep(3)
  print("線程屬性測試")

t = Thread(target=fun, name = "Tarena")

# 主線程退出分支線程也退出
t.setDaemon(True)

t.start()

t.setName("Tedu")
print("Name:",t.getName())  # 線程名稱
print("Alive:",t.is_alive())  # 線程生命週期
print("is Daemon",t.isDaemon()) # 主進程隨着分支進程退出

自定義線程類

  1. 繼承Thread類
  2. 運行Thread類中的__init__方法以獲取父類屬性
  3. 重寫run方法

使用方法

  1. 實例化對象
  2. 調用start自動化執行run方法
  3. 調用join回收線程
from threading import Thread

class ThreadClass(Thread):
  # 重寫父類init
  def __init__(self, *args, **kwargs):
    self.attr = args[0]
    super().__init__()    # 加載父類init

  def fun1(self):
    print("函數1")

  def fun2(self):
    print("函數2")

  # 重寫run,邏輯調用
  def run(self):
    self.fun1()
    self.fun2()


t = ThreadClass("abc")
t.start()
t.join()

# 函數1
# 函數2

同步互斥

線程間通訊方法

1.通訊方法:線程間使用全局變量進行通訊

2. 共享資源爭奪

  • 共享資源:多個進程或者線程均可以操做的資源稱爲共享資源。對共享資源的操做代碼段稱爲臨界區。
  • 影響 :對共享資源的無序操做可能會帶來數據的混亂,或者操做錯誤。此時每每須要同步互斥機制協調操做順序。

3. 同步互斥機制

同步 : 同步是一種協做關係,爲完成操做,多進程或者線程間造成一種協調,按照必要的步驟有序執行操做。

互斥 : 互斥是一種制約關係,當一個進程或者線程佔有資源時會進行加鎖處理,此時其餘進程線程就沒法操做該資源,直到解鎖後才能操做。

線程同步互斥方法

線程Event

from threading import Event

e = Event()      建立線程event對象

e.wait([timeout])    阻塞等待e被set

e.set()        設置e,使wait結束阻塞

e.clear()        使e回到未被設置狀態

e.is_set()       查看當前e是否被設置

from threading import Thread,Event

s = None  # 用於通訊
e = Event() # 建立event對象

def 楊子榮():
  print("楊子榮前來拜山頭")
  global s
  s = "天王蓋地虎"
  e.set()  # 對e設置

t = Thread(target=楊子榮)
t.start()

print("說對口令就是本身人")
e.wait()  # 阻塞等待口令說出
if s == '天王蓋地虎':
  print("寶塔鎮河妖")
  print("確認過眼神,你是對的人")
else:
  print("打死他...")


t.join()

線程鎖 Lock

from threading import Lock

lock = Lock()   建立鎖對象

lock.acquire()   上鎖 若是lock已經上鎖再調用會阻塞

lock.release()   解鎖

with lock:    # 上鎖

...

...

      with代碼塊結束自動解鎖

from threading import Thread,Lock

a = b = 0
lock = Lock() # 定義鎖

def value():
  while True:
    lock.acquire()  # 上鎖
    if a != b:
      print("a = %d,b = %d"%(a,b))
    lock.release() # 解鎖

t = Thread(target = value)
t.start()

while True:   # 上鎖
  with lock:
    a += 1
    b += 1
              # 自動解鎖
t.join()

python線程的GIL問題

GIL (全局解釋器鎖)

python ---》 支持線程操做 ---》IO的同步和互斥 --》 加鎖 ----》 超級鎖,給解釋器加鎖

後果:一個解釋器,同一時刻只解釋一個線程,此時其餘線程須要等待。大大下降了python線程的執行效率

python GIL問題解決方案
* 修改c解釋器
* 儘可能使用多進程進行並行操做
* python線程能夠用在高延遲多阻塞的IO情形
* 不使用cpython  c# java作解釋器

效率測試

分別測試 多進程 多線程 單進程執行相同的IO操做和CPU

#計算密集
def count(x,y):
    c = 0
    while c < 7000000:
        x += 1
        y += 1
        c += 1

#io密集
def write():
    f = open("test.txt",'w')
    for x in range(2000000):
        f.write("hello world\n")
    f.close()

def read():
    f = open("test.txt")
    lines = f.readlines()
    f.close()
View Code

操做的時間

#單進程程序
from test import *
import time 

# t = time.time()
# for i in range(10):
#     count(1,1)
# print("Line cpu:",time.time() - t)


t = time.time()
for i in range(10):
    write()
    read()
print("Line IO:",time.time() - t)
View Code

Line cpu: 8.15166711807251
Line IO: 6.841825246810913

from test import * 
import threading 
import time 

counts = []

t = time.time()

for x in range(10):
    th = threading.Thread(target = count,args = (1,1))
    th.start()
    counts.append(th)

for i in counts:
    i.join()
print("Thread cpu",time.time() - t)
View Code
from test import * 
import threading 
import time 

counts = []

def io():
    write()
    read()

t = time.time()

for x in range(10):
    th = threading.Thread(target = io)
    th.start()
    counts.append(th)

for i in counts:
    i.join()
print("Thread IO",time.time() - t)
View Code

Thread cpu 8.414522647857666
Thread IO 6.023292541503906

from test import * 
import multiprocessing 
import time 

counts = []

t = time.time()

for x in range(10):
    th = multiprocessing.Process\
    (target = count,args = (1,1))
    th.start()
    counts.append(th)

for i in counts:
    i.join()
print("Process cpu",time.time() - t)
View Code
from test import * 
import multiprocessing 
import time 

counts = []

def io():
    write()
    read()

t = time.time()

for x in range(10):
    th = multiprocessing.Process(target = io)
    th.start()
    counts.append(th)

for i in counts:
    i.join()
print("Process IO",time.time() - t)
View Code

Process cpu 4.079084157943726
Process IO 3.2132551670074463

進程和線程的區別和聯繫

  1. 二者都是多任務編程的方式,都可以使用計算機的多核
  2. 進程的建立刪除要比線程消耗更多的計算機資源
  3. 進程空間獨立,數據安全性好,有專門的進程間通訊方法
  4. 線程使用全局變量通訊,更加簡單,可是須要同步互斥操 做
  5.  一個進程能夠包含多個線程,線程共享進程的空間資源
  6.  進程線程都獨立執行,有本身的特有資源如屬性,id, 命令集等

使用狀況:

  • 一個進程中併發任務比較多,比較簡單,適合使用多線程
  • 若是數據程序比較複雜,特別是可能多個任務通訊比較多 的時候,要考慮到使用線程同步互斥的複雜性
  • 多個任務存在明顯差別,和功能分離的時候沒有必要必定 寫入到一個進程中
  • 使用python考慮線程GIL問題
相關文章
相關標籤/搜索