Python——程序、執行緒、與協程
阿新 • • 發佈:2018-12-14
程序
程序就是一個執行中的程式,是系統的資源分配和執行排程的一個基本單位。由於cpu的多工時間片輪轉工作機制,所以同一時刻內一個cpu核心只能有一個程序在執行。
linux下建立程序
import os
print os.getpid # 獲取當前程序id
pid = os.fork() # 建立一個子程序
# fork 後會產生兩次返回值,分別是給父程序和子程序的,如果處於子程序,那麼這個返回值永遠為0,如果處於主程序,那麼這個值就是子程序的pid
# 可以理解為分家後,給了原來家庭的戶口本,又給了新家庭的戶口本
if pid == 0:
# gitppid 獲取父程序pid
print "當前處於子程序:%s,父程序:%s" % (os.getpid(),os.getppid())
else:
print "當前處於父程序:%s,子程序:%s" % (os.getpid(), pid)
windows下建立程序
from multiprocessing import Process
import os
def child_process(name):
print "我是子程序%s:%s" % (name,os.getpid())
if __name__=='__main__':
print ('父程序 %d' % os.getpid())
p = Process(target=run_proc,args=('test',))
p.start()
# join()方法使等待子程序結束後再往下執行,可以用於程序間的同步
p.join()
# p.is_alive() 判斷程序例項是否還在執行
# p.terminate()不管任務是否完成,立即終止
程序池
from multiprocessing import Pool
import os,time,random
def worker(msg):
print "執行%s,程序號:%s" % (msg, os.getpid())
pool = Pool(5) # 定義一個程序池,最大程序5
for i in range(0,10):
# apply_async 阻塞方式執行
pool.apply_async(worker,(i,))
# apply 非阻塞方式執行
pool.apply(worker,(i,))
pool.close()
pool.join()
程序通訊
from multiprocessing import Process,Queue
def q_write(q,data):
for v in data:
q.put(v)
def q_read(q):
while True:
if not q.empty():
value = q.get(True)
print "read data: %s"%value
else:
break
if __name__='__main_':
q = Queue()
# 如果是程序池使用
#from multiprocessing import Manager
#q = Manager().Queue()
qw = Process(target=q_write,args=(q,['a','b','c']))
qr = Process(target=q_read,args=(q,))
qw.start()
qw.join()
qr=start()
qr=join()
在多程序中,每個程序中所有資料(包括全域性變數)都各自擁有一份,互不影響。
執行緒
執行緒是程序中的一個實體,是被系統獨立排程和分派的基本單位,執行緒自己不擁有系統資源,與其他執行緒共享程序所擁有的全部資源。一個程序至少包含一個執行緒
建立執行緒
import threading
def run():
print 'thread %s running' % threading.current_thread().name
t = threading.Thread(target=loop,name='LoopThread')
t.start()
t.join()
由於程序中資料線上程之間是共享的,所以多個執行緒可能會同時對資料檔案進行讀取修改,這樣一來就無法保證了資料的安全性,所以對資料操作時還需要引入鎖的概念
# 無鎖版
import threading
test_num = 10
def change(num):
global test_num
test_num = test_num + num
test_num = test_num - num
def change_time(n):
for i in range(10000):
change(n)
t1 = threading.Thread(target=change_time,args=(2,))
t2 = threading.Thread(target=change_time,args=(3,))
t1.start()
t2.start()
t1.join()
t2.join()
print test_num
# 有鎖版
import threading
lock = threading.Lock()
test_num = 10
def change(num):
global test_num
test_num = test_num + num
test_num = test_num - num
def change_time(n):
for i in range(10000):
# 加鎖
lock.acquire()
try:
change(n)
finally:
# 釋放鎖
lock.release()
t1 = threading.Thread(target=change_time,args=(2,))
t2 = threading.Thread(target=change_time,args=(3,))
t1.start()
t2.start()
t1.join()
t2.join()
print test_num
執行緒的區域性變數
1.設定一個全域性字典變數,以執行緒作為key,執行緒的私有變數作為value
2.使用 threading.local() 建立全域性 ThreadLocal 物件,然後將現成的私有變數繫結到該物件上。
協程
協程本質上是一個單執行緒,協程間可以中斷去執行另外一個程式,執行完後再返回。
由於處在一個執行緒內,所以不存在讀寫衝突,控制共享資源不用加鎖,更不需用進行執行緒切換。
在python,yield其實使用的就是協程思想,但yield對協程的支援並不完善。
第三方庫gevent則提供了比較完善的支援。
from gevent import monkey
# 修改python自帶的一些標準庫
monkey.patch_socket()
def f(n):
for i in range(n):
print gevent.getcurrent(), i
# gevent.sleep(0) 交出控制權
g1 = gevent.spawn(f, 5)
g2 = gevent.spawn(f, 5)
g3 = gevent.spawn(f, 5)
g1.join()
g2.join()
g3.join()
# 3個greenlet依次執行