程式:資源的集合

  執行緒:操作CPU的最小除錯單位

    最簡單的多執行緒例項如下:

#!/usr/bin/python
#Author:sean

#執行緒有2種呼叫方式,如下:
#直接呼叫
import threading
import time

def run(n):
    print("task ",n)
    time.sleep(2)

if __name__ == `__main__`:
    t1 = threading.Thread(target=run,args=("t1",))  #生成一個執行緒例項
    t2 = threading.Thread(target=run,args=("t2",))  #生成另一個執行緒例項
    t1.start()  #啟動執行緒
    t2.start()  #啟動另一個執行緒

    print(t1.getName()) #獲取執行緒名
    print(t2.getName())

run("t1")
run("t2")

#繼承式呼叫
class MyThread(threading.Thread):
    def __init__(self,num,sleep_time):
        super(MyThread,self).__init__()
        self.num = num
        self.sleep_time = sleep_time
    def run(self):  #定義每個執行緒要執行的函式
        print("running on number:%s"% self.num)
        time.sleep(self.sleep_time)
        print("task done,",self.num)

if __name__ == `__main__`:
    t1 = MyThread("t1",2)
    t2 = MyThread("t2",4)
    t1.start()
    t2.start()

    t1.join()
    t2.join()
    print("The main")

    print(t1.getName())
    print(t2.getName())

  程式與執行緒的執行速度沒有可比性

  程式至少包含一個執行緒

  python中的執行緒和程式均是使用的作業系統的原生執行緒與程式

  原生程式與原生執行緒是由作業系統維護與管理的

  python中的多執行緒是偽多執行緒,實際上同一時間只有一個執行緒在執行

  python中的多執行緒實質上就是一個單執行緒中上下文不停切換的效果表現形式

    IO操作不佔用CPU,如從硬碟中讀取資料

    計算佔用CPU,如1+1

  什麼時候會用到偽多執行緒呢?如何提高效率?

    python多執行緒不適合CPU密集操作型的任務

   python多執行緒適合於IO操作密集型的任務,如socket

  執行緒間記憶體是共享的

  執行緒同一時間修改同一份資料時必須加鎖(mutex互斥鎖)

  遞迴鎖:鎖中有鎖,進2道門的例子

  join:等待一個執行緒執行結束

def run(n):
    print("run thread...")
    
t = threading.Thread(target=run,args=(n,))
t.start()
t.join()

  訊號量:同一時間允許多個執行緒來操作

  執行緒間切換時會將上下文和棧儲存到CPU的暫存器中

  守護執行緒:服務於非守護執行緒(皇帝與宦官的關係,皇帝死了,官宦要殉葬)

  佇列的作用:

    實現程式的解耦(使程式之間實現鬆耦合)

    提高處理效率

#!/usr/bin/python
#Author:sean

import queue
#先進先出方式FIFO
q1 = queue.Queue()

q1.put(`d1`)
q1.put(`d2`)
q1.put(`d3`)
print(q1.qsize())
q1.get()
q1.get()
print(q1.qsize())
print(q1.get_nowait())
q1.get_nowait()

#後進先出方式(賣水果例子)
q2 = queue.LifoQueue() #Lifo即Last in first out
q2.put(`d1`)
q2.put(`d2`)
q2.put(`d3`)
print(q2.qsize())
q2.get()
q2.get()
print(q2.qsize())
print(q2.get_nowait())
q2.get_nowait()

#按優先順序來處理的方式
q3 = queue.PriorityQueue()   #儲存資料時可設定優先順序的佇列
q3.put((-1,"haha"))
q3.put((5,"tom"))
q3.put((10,"sean"))
q3.put((0,"jerry"))
print(q3.get())
print(q3.get())
print(q3.get())
print(q3.get())

  列表與佇列區別:

    從列表中取一個資料,相當於是複製了一份列表中的資料,列表中的後設資料並沒有被改動

    從佇列中取一個資料,取走後佇列中就沒了有這個被取的資料

  生產者消費者模型:

#!/usr/bin/python
#Author:sean

import threading
import time
import queue

q = queue.Queue(maxsize=10)

def Producer(name):
    count = 1
    while True:
        q.put("骨頭%s" % count)
        print("生產了骨頭",count)
        count += 1
        time.sleep(0.1)

def  Consumer(name):
    #while q.qsize()>0:
    while True:
        print("[%s] 取到[%s] 並且吃了它..." %(name, q.get()))
        time.sleep(1)

p = threading.Thread(target=Producer,args=("Sean",))
c = threading.Thread(target=Consumer,args=("Jason",))
c1 = threading.Thread(target=Consumer,args=("小王",))
c2 = threading.Thread(target=Consumer,args=("Jerry",))
c3 = threading.Thread(target=Consumer,args=("Tom",))

p.start()
c.start()
c1.start()
c2.start()
c3.start()

 事件:event

    紅綠燈例子:

#!/usr/bin/python
#Author:sean

import time
import threading

event = threading.Event()

def lighter():
    count = 0
    event.set() #先設為綠燈
    while True:
        if count > 5 and count < 10:  #改成紅燈
            event.clear()   #把標誌位清空
            print(" 33[41;1mred light is on... 33[0m")
        elif count > 10:
            event.set() #變綠燈
            count = 0
        else:
            print(" 33[42;1mgreen light is on... 33[0m")
        time.sleep(1)
        count += 1

def car(name):
    while True:
        if event.is_set():  #代表當前是綠燈
            print("[%s] running..."% name)
            time.sleep(1)
        else:
            print("[%s] sees red light,waiting..."% name)
            event.wait()
            print(" 33[34;1m[%s] green light is on,start going... 33[0m"% name)

light = threading.Thread(target=lighter,)
light.start()

car1 = threading.Thread(target=car,args=(`Tesla`,))
car1.start()

  python中的多程式:

    程式之間是獨立的,記憶體是獨享

  多程式例子:

#!/usr/bin/python
#Author:sean

import multiprocessing
import time

def f(name):
    time.sleep(2)
    print("hello",name)

if __name__ == `__main__`:
    for i in range(10):
        p = multiprocessing.Process(target=f,args=(`bob %s`% i,))
        p.start()
    # p.join()

  獲取程式ID:

#!/usr/bin/python
#Author:sean

from multiprocessing import Process
import os


def info(title):
    print(title)
    print(`module name:`, __name__)
    print(`parent process:`, os.getppid())
    print(`process id:`, os.getpid())
    print("

")


def f(name):
    info(` 33[31;1mcalled from child process function f 33[0m`)
    print(`hello`, name)

if __name__ == `__main__`:
    info(` 33[32;1mmain process line 33[0m`)
    p = Process(target=f, args=(`bob`,))
    p.start()
    # p.join()

  在python中,每個子程式都是由其父程式啟動的

  程式間通訊:

   不同程式間記憶體是不共享的,要想實現兩個程式間的資料交換,可以使用以下方法:

  1、Queues

    使用方法與threading裡的queue差不多

#!/usr/bin/python
#Author:sean

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()

  2、Pipes

  The Pipe() function returns a pair of connection objects connected by a pipe which by default is duplex(two-way).For example:

#!/usr/bin/python
#Author:sean

from multiprocessing import Process,Pipe

def f(conn):
    conn.send([42,None,`hello from child`])
    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()

  上面所說的Queues和Pipes只是實現了程式之間的資料交換,並沒有實現程式間的記憶體共享,要想實現程式之間記憶體共享,則要使用Managers

  3、Managers

  A manager object returnd by Manager() controls a server process which holds Python objects and allows other processes to manipulate them using proxies.

  A manager returned by Manager() will support following types:

  list,dict,Namespace,Lock,RLock,Semaphore,BoundedSemaphore,Condition,Event,Barrier,Queue,Value and Array.For example:

#!/usr/bin/python
#Author:sean

from multiprocessing import Process, Manager
import os

def f(d, l):
    d[1] = `1`
    d[`2`] = 2
    d["pid%s" %os.getpid()] = os.getpid()
    l.append(1)
    print(l,d)


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()
        l.append("from parent")
        print(d)
        print(l)
#!/usr/bin/python
#Author:sean

from multiprocessing import Process, Manager
import os
def f(d, l):
    d[os.getpid()] =os.getpid()
    l.append(os.getpid())
    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)

  程式同步

  without using the lock output from the different processes is liable to get all mixed up.

#!/usr/bin/python
#Author:sean

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()

  程式間也是有鎖的概念的。

  程式之間記憶體是獨享的,獨立的,那為什麼還要鎖呢?

  對於python中的程式而言,程式間的記憶體是獨享的,但是程式的標準輸出是一致的,說白了螢幕是共享的。那麼如果同一時間多個程式都爭著列印資訊到螢幕,如果沒有鎖的話就會出錯,就會出現程式1還沒列印完的時候程式2插進來了,導致最後的輸出結果不正確。

  程式池

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

  程式池有兩個方法:

  1、apply(同步執行、序列)

  2、apply_async(非同步執行、並行)

#!/usr/bin/env python
#author:sean

from  multiprocessing import Process, Pool,freeze_support
#這裡的freeze_support只在windows中時需要匯入
import time
import os

def Foo(i):
    time.sleep(2)
    print("in process",os.getpid())
    return i + 100

def Bar(arg):
    print(`-->exec done:`, arg,os.getpid())

if __name__ == `__main__`:
    #freeze_support()  #這一句只在windows中時需要
    pool = Pool(processes=5) #允許程式池同時放入5個同時存在的程式
    print("主程式",os.getpid())
    for i in range(10):
        pool.apply_async(func=Foo, args=(i,), callback=Bar) 
        #callback=回撥,由主程式執行回撥,常用於主程式與子程式共享資料庫連線的時候
        #當主程式已經建立了資料庫連線以後,子程式可以直接通過這個連線操作同一個資料庫例項
        #pool.apply(func=Foo, args=(i,)) #序列
        #pool.apply_async(func=Foo, args=(i,)) #序列
    print(`end`)
    pool.close()
    pool.join() #程式池中程式執行完畢後再關閉,如果註釋,那麼程式直接關閉。.join()