1. 程式人生 > >Python——程序、執行緒、與協程

Python——程序、執行緒、與協程

程序

程序就是一個執行中的程式,是系統的資源分配和執行排程的一個基本單位。由於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依次執行