python學習day8

目錄python

1、異常算法

2、多線程編程

3、守護線程與join多線程

4、GIL與多線程鎖併發

5、遞歸鎖與信號量app

6、線程間同步與交互dom

7、多進程async

8、進程間通訊與數據共享函數

9、進程池測試


1、異常

一、異常處理

在編程過程當中爲了增長友好性,在程序出現bug時通常不會將錯誤信息顯示給用戶,而是現實一個提示的頁面,通俗來講就是不讓用戶看見大黃頁!!!

try:
    pass
except Exception,ex:
    pass

需求:將用戶輸入的兩個數字相加

while True:
    num1 = raw_input('num1:')
    num2 = raw_input('num2:')
    try:
        num1 = int(num1)
        num2 = int(num2)
        result = num1 + num2
    except Exception, e:
        print '出現異常,信息以下:'
        print e

 

二、異常種類

AttributeError 試圖訪問一個對象沒有的樹形,好比foo.x,可是foo沒有屬性x
IOError 輸入/輸出異常;基本上是沒法打開文件
ImportError 沒法引入模塊或包;基本上是路徑問題或名稱錯誤
IndentationError 語法錯誤(的子類) ;代碼沒有正確對齊
IndexError 下標索引超出序列邊界,好比當x只有三個元素,卻試圖訪問x[5]
KeyError 試圖訪問字典裏不存在的鍵
KeyboardInterrupt Ctrl+C被按下
NameError 使用一個還未被賦予對象的變量
SyntaxError Python代碼非法,代碼不能編譯(我的認爲這是語法錯誤,寫錯了)
TypeError 傳入對象類型與要求的不符合
UnboundLocalError 試圖訪問一個還未被設置的局部變量,基本上是因爲另有一個同名的全局變量,
致使你覺得正在訪問它
ValueError 傳入一個調用者不指望的值,即便值的類型是正確的
Exception爲抓取全部異常(不能抓取語法的錯誤)
3.異常其餘結構
try:
    # 主代碼塊
    pass
except KeyError,e:
    # 異常時,執行該塊
    pass
else:
    # 主代碼塊執行完,執行該塊
    pass
finally:
    # 不管異常與否,最終執行該塊
    pass

四、主動觸發異常

try:
    raise Exception('錯誤了。。。')
except Exception,e:
    print e

五、自定義異常

class exception_handler(Exception):
    def __init__(self,msg):
        self.message = msg
    def __str__(self):
        return self.message
a = 1
try:
    raise exception_handler('這是一個異常')
except exception_handler as msg:
    print(msg)

六、Finally及斷言

a = 1
try:
    assert a== 2 #斷言,對條件進行判斷,若是條件成立向下執行。
    print('正常執行')
except Exception as msg:
    print(msg)
else:#沒出現異常打印信息
    print('這是一個測試信息')
finally:#不論是否出現異常都打印信息
    print('無論條件是否成立,都打印此條信息!')

2、多線程

Threading用於提供線程相關的操做,線程是應用程序中工做的最小單元。

線程有兩種調用方式:

直接調用:

import threading
import time
 
def sayhi(num): #定義每一個線程要運行的函數
 
    print("running on number:%s" %num)
 
    time.sleep(3)
 
if __name__ == '__main__':
 
    t1 = threading.Thread(target=sayhi,args=(1,)) #生成一個線程實例
    t2 = threading.Thread(target=sayhi,args=(2,)) #生成另外一個線程實例
 
    t1.start() #啓動線程
    t2.start() #啓動另外一個線程
 
    print(t1.getName()) #獲取線程名
    print(t2.getName())

繼承式調用

import threading
import time
 
 
class MyThread(threading.Thread):
    def __init__(self,num):
        threading.Thread.__init__(self)
        self.num = num
 
    def run(self):#定義每一個線程要運行的函數
 
        print("running on number:%s" %self.num)
 
        time.sleep(3)
 
if __name__ == '__main__':
 
    t1 = MyThread(1)
    t2 = MyThread(2)
    t1.start()
    t2.start()

上述代碼建立了10個「前臺」線程,而後控制器就交給了CPU,CPU根據指定算法進行調度,分片執行指令。

更多方法:

  • start            線程準備就緒,等待CPU調度
  • setName      爲線程設置名稱
  • getName      獲取線程名稱
  • setDaemon   設置爲後臺線程或前臺線程(默認)
                       若是是後臺線程,主線程執行過程當中,後臺線程也在進行,主線程執行完畢後,後臺線程不論成功與否,均中止
                        若是是前臺線程,主線程執行過程當中,前臺線程也在進行,主線程執行完畢後,等待前臺線程也執行完成後,程序中止
  • join              逐個執行每一個線程,執行完畢後繼續往下執行,該方法使得多線程變得無心義
  • run              線程被cpu調度後自動執行線程對象的run方法

3、守護線程與join

 

import time
import threading
 
def run(n):
 
    print('[%s]------running----\n' % n)
    time.sleep(2)
    print('--done--')
 
def main():
    for i in range(5):
        t = threading.Thread(target=run,args=[i,])
        #time.sleep(1)
        t.start()
        t.join(1)
        print('starting thread', t.getName())
 
 
m = threading.Thread(target=main,args=[])
m.setDaemon(True) #將主線程設置爲Daemon線程,它退出時,其它子線程會同時退出,不論是否執行完任務
m.start()
#m.join(timeout=2)
print("---main thread done----")

4、GIL與多線程鎖

互斥鎖(Mutex)

一個進程下能夠啓動多個線程,多個線程共享父進程的內存空間,也就意味着每一個線程能夠訪問同一份數據,此時,若是2個線程同時要修改同一份數據,會出現什麼情況?

未加鎖代碼:

import time
import threading
 
def addNum():
    global num #在每一個線程中都獲取這個全局變量
    print('--get num:',num )
    time.sleep(1)
    num  -=1 #對此公共變量進行-1操做
 
num = 100  #設定一個共享變量
thread_list = []
for i in range(100):
    t = threading.Thread(target=addNum)
    t.start()
    thread_list.append(t)
 
for t in thread_list: #等待全部線程執行完畢
    t.join()
 
 
print('final num:', num )

正常來說,這個num結果應該是0, 但在python 2.7上多運行幾回,會發現,最後打印出來的num結果不老是0,爲何每次運行的結果不同呢? 哈,很簡單,假設你有A,B兩個線程,此時都 要對num 進行減1操做, 因爲2個線程是併發同時運行的,因此2個線程頗有可能同時拿走了num=100這個初始變量交給cpu去運算,當A線程去處完的結果是99,但此時B線程運算完的結果也是99,兩個線程同時CPU運算的結果再賦值給num變量後,結果就都是99。那怎麼辦呢? 很簡單,每一個線程在要修改公共數據時,爲了不本身在還沒改完的時候別人也來修改此數據,能夠給這個數據加一把鎖, 這樣其它線程想修改此數據時就必須等待你修改完畢並把鎖釋放掉後才能再訪問此數據。

*注:不要在3.x上運行,不知爲何,3.x上的結果老是正確的,多是自動加了鎖

加鎖版本:

import time
import threading
 
def addNum():
    global num #在每一個線程中都獲取這個全局變量
    print('--get num:',num )
    time.sleep(1)
    lock.acquire() #修改數據前加鎖
    num  -=1 #對此公共變量進行-1操做
    lock.release() #修改後釋放
 
num = 100  #設定一個共享變量
thread_list = []
lock = threading.Lock() #生成全局鎖
for i in range(100):
    t = threading.Thread(target=addNum)
    t.start()
    thread_list.append(t)
 
for t in thread_list: #等待全部線程執行完畢
    t.join()
 
print('final num:', num )

5、遞歸鎖與信號量

遞歸鎖(RLock)

說白了就是在一個大鎖中還要再包含子鎖

import threading,time
 
def run1():
    print("grab the first part data")
    lock.acquire()
    global num
    num +=1
    lock.release()
    return num
def run2():
    print("grab the second part data")
    lock.acquire()
    global  num2
    num2+=1
    lock.release()
    return num2
def run3():
    lock.acquire()
    res = run1()
    print('--------between run1 and run2-----')
    res2 = run2()
    lock.release()
    print(res,res2)
 
 
if __name__ == '__main__':
 
    num,num2 = 0,0
    lock = threading.RLock()
    for i in range(10):
        t = threading.Thread(target=run3)
        t.start()
 
while threading.active_count() != 1:
    print(threading.active_count())
else:
    print('----all threads done---')
    print(num,num2)

 

信號量(Semaphore)

互斥鎖 同時只容許一個線程更改數據,而Semaphore是同時容許必定數量的線程更改數據 ,好比廁全部3個坑,那最多隻容許3我的上廁所,後面的人只能等裏面有人出來了才能再進去。

import threading,time
 
def run(n):
    semaphore.acquire()
    time.sleep(1)
    print("run the thread: %s\n" %n)
    semaphore.release()
 
if __name__ == '__main__':
 
    num= 0
    semaphore  = threading.BoundedSemaphore(5) #最多容許5個線程同時運行
    for i in range(20):
        t = threading.Thread(target=run,args=(i,))
        t.start()
 
while threading.active_count() != 1:
    pass #print threading.active_count()
else:
    print('----all threads done---')
    print(num)

6、線程間同步與交互(Events)

經過Event來實現兩個或多個線程間的交互,下面是一個紅綠燈的例子,即起動一個線程作交通指揮燈,生成幾個線程作車輛,車輛行駛按紅燈停,綠燈行的規則。

import threading,time
import random
def light():
    if not event.isSet():
        event.set() #wait就不阻塞 #綠燈狀態
    count = 0
    while True:
        if count < 10:
            print('\033[42;1m--green light on---\033[0m')
        elif count <13:
            print('\033[43;1m--yellow light on---\033[0m')
        elif count <20:
            if event.isSet():
                event.clear()
            print('\033[41;1m--red light on---\033[0m')
        else:
            count = 0
            event.set() #打開綠燈
        time.sleep(1)
        count +=1
def car(n):
    while 1:
        time.sleep(random.randrange(10))
        if  event.isSet(): #綠燈
            print("car [%s] is running.." % n)
        else:
            print("car [%s] is waiting for the red light.." %n)
if __name__ == '__main__':
    event = threading.Event()
    Light = threading.Thread(target=light)
    Light.start()
    for i in range(3):
        t = threading.Thread(target=car,args=(i,))
        t.start()

7、多進程

from multiprocessing import Process
import threading
import time
  
def foo(i):
    print 'say hi',i
  
for i in range(10):
    p = Process(target=foo,args=(i,))
    p.start()

注意:因爲進程之間的數據須要各自持有一份,因此建立進程須要的很是大的開銷。


8、進程間通訊與數據共享

不一樣進程間內存是不共享的,要想實現兩個進程間的數據交換,能夠用如下方法:

Queues

使用方法跟threading裏的queue差很少

from multiprocessing import Process, Queue
 
def f(q):
    q.put([42, None, 'hello'])
 
if __name__ == '__main__':
    q = Queue()
    p = Process(target=f, args=(q,))
    p.start()
    print(q.get())    # prints "[42, None, 'hello']"
    p.join()

 

Pipes

from multiprocessing import Process, Pipe
 
def f(conn):
    conn.send([42, None, 'hello'])
    conn.close()
 
if __name__ == '__main__':
    parent_conn, child_conn = Pipe()
    p = Process(target=f, args=(child_conn,))
    p.start()
    print(parent_conn.recv())   # prints "[42, None, 'hello']"
    p.join()

 

Managers

from multiprocessing import Process, Manager
 
def f(d, l):
    d[1] = '1'
    d['2'] = 2
    d[0.25] = None
    l.append(1)
    print(l)
 
if __name__ == '__main__':
    with Manager() as manager:
        d = manager.dict()
 
        l = manager.list(range(5))
        p_list = []
        for i in range(10):
            p = Process(target=f, args=(d, l))
            p.start()
            p_list.append(p)
        for res in p_list:
            res.join()
 
        print(d)
        print(l)

 

Array

from multiprocessing import Process,Array
temp = Array('i', [11,22,33,44])
 
def Foo(i):
    temp[i] = 100+i
    for item in temp:
        print i,'----->',item
 
for i in range(2):
    p = Process(target=Foo,args=(i,))
    p.start()

 

進程同步

from multiprocessing import Process, Lock
 
def f(l, i):
    l.acquire()
    try:
        print('hello world', i)
    finally:
        l.release()
 
if __name__ == '__main__':
    lock = Lock()
 
    for num in range(10):
        Process(target=f, args=(lock, num)).start()

9、進程池

進程池內部維護一個進程序列,當使用時,則去進程池中獲取一個進程,若是進程池序列中沒有可供使用的進進程,那麼程序就會等待,直到進程池中有可用進程爲止。

進程池中有兩個方法:

  • apply
  • apply_async
from  multiprocessing import Process,Pool
import time
 
def Foo(i):
    time.sleep(2)
    return i+100
 
def Bar(arg):
    print('-->exec done:',arg)
 
pool = Pool(5)
 
for i in range(10):
    pool.apply_async(func=Foo, args=(i,),callback=Bar)
    #pool.apply(func=Foo, args=(i,))
 
print('end')
pool.close()
pool.join()#進程池中進程執行完畢後再關閉,若是註釋,那麼程序直接關閉。
相關文章
相關標籤/搜索