程序並不能單獨運行,只有將程序裝載到內存中,系統爲它分配資源才能運行,而這種執行的程序就稱之爲進程。python
程序和進程的區別就在於:程序是指令的集合,它是進程運行的靜態描述文本;進程是程序的一次執行活動,屬於動態概念。編程
簡單點說就是:進程就是一個程序在一個數據集上的一次動態執行過程。安全
一個時間點只能作一件事,不能同時幹兩件及以上的事;數據結構
在執行的過程進程若是阻塞,例如等待輸入,整個進程就會掛起,即便進程中有些工做不依賴於輸入的數據,也將沒法執行。多線程
線程也叫輕量級進程,它是一個基本的CPU執行單元,也是程序執行過程當中的最小單元;併發
一條線程指的是進程中一個單一順序的控制流,一個進程中能夠併發多個線程,每條線程並行執行不一樣的任務;app
突破一個進程只能幹同樣事的缺陷,使到進程內併發成爲可能;async
線程的引入減少了程序併發執行時的開銷,提升了操做系統的併發性能; ide
線程是執行的指令集 , 進程是資源的集合函數
線程的啓動速度要比進程的啓動速度要快
兩個線程的執行速度是同樣的,進程與線程的運行速度是沒有可比性的
線程共享建立它的進程的內存空間 , 進程的內存是獨立的
兩個線程共享的數據都是同一份數據 , 兩個子進程的數據不是共享的 , 並且數據是獨立的
同一個進程的線程之間能夠直接交流 , 同一個主進程的多個子進程之間是不能夠進行交流 , 若是兩個進程之間須要通訊 , 就必需要經過一箇中間代理來實現
一個新的線程很容易被建立 , 一個新的進程建立須要對父進程進行一次克隆
一個線程能夠控制和操做同一個進程裏的其餘線程 , 線程與線程之間沒有隸屬關係 , 可是進程只能操做子進程
改變主線程 , 有可能會影響到其餘線程的行爲 , 可是對於父進程的修改是不會影響子進程
直接調用:
import threading import time def run(n): #定義線程要運行的函數 print('task',n) time.sleep(2) if __name__ == '__main__': t1 = threading.Thread(target=run,args=(1,)) #生成一個線程 t2 = threading.Thread(target=run,args=(2,)) #生成一個另外線程 t1.start() # 啓動線程 t2.start() # 啓動另一個線程 print(t1.getName()) # 獲取線程名 print(t2.getName()) print('I am main thread') #主線程 #這個進程裏面有三個線程,1個主線程,t1,t2兩個子線程 #子線程和主線程是同步開啓的,主線程結束後,要等子線程所有結束後,進程纔會關閉
PS:線程相關的方法:
start 線程準備就緒,等待CPU調度 setName 爲線程設置名稱 getName 獲取線程名稱 run 線程被cpu調度後自動執行線程對象的run方法 # 下面會講到 setDaemon 將線程聲明爲守護線程,必須在start() 方法調用以前設setDaemon(),只要主線程完成了,無論子線程是否完成,都要和主線程一塊兒退出
join 逐個執行每一個線程,執行完畢後繼續往下執行,該方法保證當前線程執行完成後再執行其它線程,使得多線程變得無心義。
繼承式調用:
import threading import time class MyThread(threading.Thread): #繼承threading,Thread模塊 def __init__(self,n): threading.Thread.__init__() #繼承父類 # 或者super(MyThread, self).__init__() self.n = n def run(self): #定義每一個線程要運行的函數,必須用run print('task',self.n) time.sleep(2) if __name__ == '__main__': t1 = MyThread(1) t2 = MyThread(2) t1.start() t2.start() print('I am main thread')
主線程:當一個程序啓動時 , 就有一個進程被操做系統建立 , 與此同時一個線程也馬上運行 , 該線程一般叫作程序的主線程;
子線程 : 由於程序是開始時就執行的 , 若是你須要再建立線程 , 那麼建立的線程就是這個主線程的子線程;
join應用:
import threading import time def run(n): print("task ",n ) time.sleep(2) start_time = time.time() t_objs = [] # 存線程實例 for i in range(10): #生成10個線程 t = threading.Thread(target=run,args=("t-%s" %i ,)) t.start() t_objs.append(t) #爲了避免阻塞後面線程的啓動,不在這裏join,先放到一個列表裏 for t in t_objs: #循環線程實例列表,等待全部線程執行完畢 t.join() print("---all threads has finished...") print("cost:",time.time() - start_time)
setDaemon應用:
import threading import time def run(n): print('task',n) time.sleep(2) print('i am 子線程') #主線程結束,setDaemon無論有沒有運行完都會被銷燬 if __name__ == '__main__': t1 = threading.Thread(target=run,args=(1,)) t2 = threading.Thread(target=run,args=(2,)) t1.setDaemon(True) #設置守護線程,放在start以前 t1.start() t2.setDaemon(True) t2.start() print('I am main thread') 結果: task 1 task 2 I am main thread
lock:若是有多個進程對同一文件進行修改 , 就會形成錯亂 , 因此咱們爲了保護文件數據的安全 , 就須要給其進行加鎖,join爲總體串行 , lock爲局部串行
Rlock(遞歸鎖):在線程間共享多個資源的時候,若是兩個線程分別佔有一部分資源而且同時等待對方的資源,就會形成死鎖,由於系統判斷這部分資源都正在使用,全部這兩個線程在無外力做用下將一直等待下去。就是解決死鎖的問題
加鎖:
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 )
互斥鎖 同時只容許一個線程更改數據,而Semaphore是同時容許必定數量的線程更改數據 ,好比食堂打飯有5個窗口,那最多隻容許5我的同時打飯,後面的人只能等裏面有人打完才能去打。
import threading, time def run(n): semaphore.acquire() time.sleep(1) print("run the thread: %s\n" % n) semaphore.release() if __name__ == '__main__': 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 else: print('----all threads done---')
Queue是python標準庫中的線程安全的隊列(FIFO)實現,提供了一個適用於多線程編程的先進先出的數據結構,即隊列,用來在生產者和消費者線程之間的信息傳遞
FIFO即First in First Out,先進先出。Queue提供了一個基本的FIFO容器,使用方法很簡單,maxsize是個整數,指明瞭隊列中能存放的數據個數的上限。一旦達到上限,插入會致使阻塞,直到隊列中的數據被消費掉。若是maxsize小於或者等於0,隊列大小沒有限制。
簡單的FIFO:
import Queue q = Queue.Queue() for i in range(5): q.put(i) while not q.empty(): print q.get()
0
1
2
3
4
LIFO即Last in First Out,後進先出。與棧的相似;
簡單的LIFO:
import Queue q = Queue.LifoQueue() for i in range(5): q.put(i) while not q.empty(): print q.get()
4
3
2
1
0
import Queue import threading class Job(object): def __init__(self, priority, description): self.priority = priority self.description = description print('Job:',description) return def __cmp__(self, other): return cmp(self.priority, other.priority) q = Queue.PriorityQueue() q.put(Job(3, 'level 3 job')) q.put(Job(10, 'level 10 job')) q.put(Job(1, 'level 1 job')) def process_job(q): while True: next_job = q.get() print('for:', next_job.description) q.task_done() workers = [threading.Thread(target=process_job, args=(q,)), threading.Thread(target=process_job, args=(q,)) ] for w in workers: w.setDaemon(True) w.start() q.join()
Job: level 3 job Job: level 10 job Job: level 1 job for: level 1 job for: level 3 job for: job: level 10 job
qsize() #看隊列大小 task_done() # 意味着以前入隊的一個任務已經完成。由隊列的消費者線程調用。
# 每個get()調用獲得一個任務,接下來的task_done()調用告訴隊列該任務已經處理完畢。若是當前一個join()正在阻塞,它將在隊列中的全部任務都處理完時恢復執行(即每個由put()調用入隊的任務都有一個對應的task_done()調用)。 join() # 阻塞調用線程,直到隊列中的全部任務被處理掉。只要有數據被加入隊列,未完成的任務數就會增長。當消費者線程調用task_done()(意味着有消費者取得任務並完成任務),未完成的任務數就會減小。當未完成的任務數降到0,join()解除阻塞。 put(item[, block[, timeout]]) # 將item放入隊列中。 # 一、若是可選的參數block爲True且timeout爲空對象(默認的狀況,阻塞調用,無超時)。 # 二、若是timeout是個正整數,阻塞調用進程最多timeout秒,若是一直無空空間可用,拋出Full異常(帶超時的阻塞調用)。 # 二、若是block爲False,若是有空閒空間可用將數據放入隊列,不然當即拋出Full異常其非阻塞版本爲put_nowait等同於put(item, False) get([block[, timeout]]) # 從隊列中移除並返回一個數據。block跟timeout參數同put方法 # 其非阻塞方法爲`get_nowait()`至關與get(False) full() #判斷隊列是否有數據 返回bool值 empty() # 若是隊列爲空,返回True,反之返回False
python線程的事件用於主線程控制其餘線程的執行,事件主要提供了三個方法 set、wait、clear。
事件處理的機制:全局定義了一個「Flag」,若是「Flag」值爲 False,那麼當程序執行 event.wait 方法時就會阻塞,若是「Flag」值爲True,那麼event.wait 方法時便再也不阻塞。
# -*- coding:utf-8 -*- # @Author : Clint import threading def do(event): print('start') event.wait() print('execute') event_obj = threading.Event() for i in range(10): t = threading.Thread(target=do, args=(event_obj,)) t.start() event_obj.clear() inp = input('input:') if inp == 'true': event_obj.set()
使得線程等待,只有知足某條件時,才釋放n個線程
def condition_func(): ret = False inp = input('>>>') if inp == '1': ret = True return ret def run(n): con.acquire() con.wait_for(condition_func) print("run the thread: %s" %n) con.release() if __name__ == '__main__': con = threading.Condition() for i in range(10): t = threading.Thread(target=run, args=(i,)) t.start()
from threading import Timer def hello(): print("hello, world") t = Timer(1, hello) t.start() # 一秒後打印
進程池內部維護一個進程序列,當使用時,則去進程池中獲取一個進程,若是進程池序列中沒有可供使用的進進程,那麼程序就會等待,直到進程池中有可用進程爲止。
進程池中有兩個方法:apply、apply_async
# -*- coding:utf-8 -*- # @Author : Clint from multiprocessing import Process, Pool import time def Foo(i): time.sleep(2) return i + 100 def Bar(arg): print(arg) pool = Pool(5) # print pool.apply(Foo,(1,)) # print pool.apply_async(func =Foo, args=(1,)).get() for i in range(10): pool.apply_async(func=Foo, args=(i,), callback=Bar) print('end') pool.close() pool.join() # 進程池中進程執行完畢後再關閉,若是註釋,那麼程序直接關閉。