Python學習之路-隨筆03 多線程/進程和協程(上篇)

  

 最近東西積攢了太多,感受再不寫進來就要炸了。python

1.多線程

1.11 關於多線程的包

相關的python包有幾個,好比thread包,到py3改爲_thread,而thread有一些問題使得不是很好用。通用的包叫threading。最近都是在用這個。安全

1.12 threading的使用和經常使用屬性

須要注意的點有生成實例好比t = threading.Thread(target=xxx, args=(xx,)),裏面有兩個參數,第一個是目標函數,第二個是相關的參數,注意類型。多線程

而後就是start啓動,join等待多線程實行完成這兩個方法。ide

#僞代碼
t1 = threading.Thread(target=fun1, args=("函數參數 1",))
t1.start()

t2 = threading.Thread(target=fun2, args=("函數參數1", "函數參數2"))
t2.start()

#等待線程
t1.join()
t2.join()

繼承threading.Thread使用,須要重寫run函數。函數

class MyThread(threading.Thread):
  def __init__(self, arg):
    super(MyThread, self).__init__()
    self.arg = arg

  def run(self):
    time.sleep(2)

其餘經常使用屬性和方法有:工具

threading.currentThread:返回當前線程變量this

threading.enumerate:返回一個包含正在運行的線程的list,正在運行的線程指的是線程啓動後,結束前的狀態spa

threading.activeCount: 返回正在運行的線程數量,效果跟 len(threading.enumerate)相同操作系統

threading.timer: 定時器,利用多線程在指定時間後啓動一個功能線程

thr.setName: 給線程設置名字

thr.getName: 獲得線程的名字

守護線程:daemon:即若是將子線程設置成守護線程,則子線程會在主線程結束的時候自動退出,通常認爲,守護線程不中要或者不容許離開主線程獨立運行

而守護線程可否有效果跟環境相關

t1 = threading.Thread(target=fun, args=() )
# 社會守護線程的方法,必須在start以前設置,不然無效
t1.setDaemon(True)
#t1.daemon = True
t1.start()

 

1.13 線程相關的問題

由於線程之間有共享狀態(資源),會有一些諸如死鎖或者同步的問題。解決方法也是大同小異,這些python裏都給出了

相應的工具。好比本身設置一個鎖/信號燈。用semphore變量,還有可重入鎖解鎖遞歸的時候申請鎖的問題等等。

線程安全不安全變量list,set,dict,安全變量queue等。

1.14 線程替代方案

替代無非是用進程或者魔改的線程包,諸如subprocess使用進程,multiprocessing用threading派生出來的,使用子進程,可使用多核或多CPU

還有一個current.future待會兒寫

2.多進程

使用的就是上面提到的線程替代方案multiprocessing,方法和threading差很少,multiprocessing.Process(target=xxx, args=(xx,)),而後一樣也能夠繼承後使用,實現方式相似多線程

還有一個就是pid和ppid,即進程ID和父進程ID,還有其餘常見的內容好比子進程和父進程共享資源啊,而子線程有本身獨立的棧空間啊之類的就不詳細描述了

還有其餘的諸如生產者-消費者模型,讀者-寫者模型等等。和上面的同樣,也不贅述了,操做系統書裏都有,寫在這沒什麼意義。

3.協程

首先來寫一下協程的定義:協程是爲非搶佔式多任務產生子程序的計算機程序組件, 協程容許不一樣入口點在不一樣位置暫停或開始執行程序。 

 在這以前先寫兩個

3.11 迭代器

有兩個概念,一是可迭代對象Iterable,二是迭代器Iterator

Iterable能夠用於for循環,二Iterator不只能夠用於for循環還能被next函數調用,能夠用isinstance函數判斷,好比list是可迭代的。

from collections import Iterable

l = [1,2,3,4]

isinstance(l, Iterable)

out:True

二者之間還能夠經過iter函數轉換

from collections import Iterator

isinstance(iter('abc'), Iterator)

out:True

3.12 生成器

好比最多見的生成器有L = [x * x for x in range(10)],g = (x * x for x in range(10))這些生成列表,元組的方法

本質是一個函數/方法,每次調用next的時候計算下一個值,最後會拋出StopIteration異常。

函數中包含yield,則叫generator

next調用,遇到yield返回

# 在函數odd中,yield負責返回
def odd():
    print("Step 1")
    yield 1
    print("Step 2")
    yield 2
    print("Step 3")
    yield 3
 
# odd() 是調用生成器
g = odd()
one = next(g)
print(one)

two = next(g)
print(two)

three = next(g)
print(three)

out:Step 1

  1

  Step 2

  2

  Step 3

  3

3.13 協程

是的,協程和生成器很像,使用yield和send。目的是合理調用各類系統資源和進行協同工做。協程之間切換耗費也很低

協程有四個狀態:

GEN_CREATED:等待開始執行

GEN_RUNNING:解釋器正在執行

GEN_SUSPENED:在yield表達式處暫停

GEN_CLOSED:執行結束

def simple_coroutine(a):
    print('-> start') 

    b = yield a # 把A丟出來給aa
    print('-> recived', a, b)

    c = yield a + b
    print('-> recived', a, b, c)

# runc
sc = simple_coroutine(5)

aa = next(sc) # 預激,準備好執行協程,程序走到yield停下
print(aa) 
bb = sc.send(6) # 5 ,6  把參數6發給b
print(bb)
cc = sc.send(7) # 5, 6, 7
print(cc)#執行不到,拋出StopIteration異常

out:

-> start

5

-> recived 5 6

11

-> recived 5 6 7

以前說過,最後會拋出一個StopIteration異常,未處理的異常會向上冒泡,傳給next函數或send函數的調用方。終止協程能夠發送某個哨符,讓協程退出,好比內置的None和Ellipsis等常量

還有兩個和異常相關的方法generator.throw(Exctpiton)和generator.close()

大概做用就是前一個會在暫停的yield出拋出指定的異常。若是生成器處理了該異常,則代碼會執行到下一個yield

而產出的值(value,異常的一個屬性)會成爲調用 generator.throw方法獲得的返回值。沒處理則往上冒泡。

第二個的做用是導致生成器在暫停的 yield 表達式處拋出 GeneratorExit 異常。若是生成器沒有處理這個異常,或者拋出了 StopIteration 異常(一般是指運行到結尾),調用方不會報錯。

若是收到 GeneratorExit 異常,生成器必定不能產出值,不然解釋器會拋出RuntimeError 異常。生成器拋出的其餘異常會向上冒泡,傳給調用方。

如下是找到的一段事例代碼

class DemoException(Exception):
    """
    custom exception
    """
    pass

def handle_exception():
    print('-> start')

    while True:
        try:
            x = yield
        except DemoException:
            print('-> run demo exception')
        else:
            print('-> recived x:', x)

    raise RuntimeError('this line should never run')

he = handle_exception()
next(he)
he.send(10) # recived x: 10
he.send(20) # recived x: 20

he.throw(DemoException) # run demo exception

he.send(40) # recived x: 40
he.close()
View Code

yield from

相對於yield,yield from就至關於在調用方和生成器之間多了一層「通道」相似的代理。(又或者說在主線程和協程之間)

使用的渠道:好比委派生成器。

1,定義一個生成器(含yield)能夠一次次的接收調用方傳來的值(經過yield)和return回去處理後的值

2,定義個委派生成器,只須要yield from 生成器便可使用並接收值

3,調用委派生成器使用

未完待續

相關文章
相關標籤/搜索