python之進程和線程(一)

概念解釋

	說到進程和線程就要引用我們下面三個點:
	1.多任務
	如果是單核CPU的情況下,比方說我們一邊開着音樂,一邊開着瀏覽器,再打着遊戲
	這個時候我們的CPU不是同事執行這個任務,而是來回快速切換,因爲我們的CPU處理
	速度是很快的,所以我們感覺不到,那四核CPU呢,如果執行八個任務,這樣也是來回切換
	,但是我們切換的時間輪更少了,8個任務之間快速來調度,效率也更高了。
	2.多進程
	操作系統分配資源的最小單位。一個線程只能屬於一個進程,而一個進程可以有多個線程,但至少有一個線程
	3.多線程
	線程是進程中的最小執行單位,它可與同屬一個進程的其它線程共享進程所擁有的全部資源
	同一進程中的多個線程之間可以併發執行

構造子進程

	from multiprocessing import Process  #用multiprocessing可以在主進程中創建子進程
	import os   #導入os模塊
	def mk_pro(name):
	    print('子進程{},id是{}'.format(name,os.getpid()))     #os.getpid():查看進程id
	if __name__ == '__main__':
	    print('父進程id是{}'.format(os.getpid()))
	    p = Process(target=mk_pro,args=('test',))   #利用Process創建子進程實例,target傳入函數,args傳入函數參數
	    #args這裏要注意,當元祖只有一個元素的時候要加上逗號,不要掉陷阱裏面了
	    print('子進程啓動')
	    p.daemon = True#將主線程設置爲Daemon線程,它退出時,其它子線程會同時退出,不管是否執行完任務
	    daemon 默認會是False,爲True則是它退出時,其它子線程會同時退出,不管是否執行完任務
	    p.start()   #啓動進程
	    p.join()    #等待子進程結束後繼續往下運行。用於進程間同步。
	    print('子進程結束')
	   這裏需要注意的是:
		   #這裏的父進程指得就是我們當前程序文件,如果不加if __name__ == '__main__':
           #則會報錯,因爲子進程在運行時是依賴於父進程的所有內容的,創建一個子進程的
           時候該子進程就會複製當前父進程的模塊。
       不加會報如下錯誤:
       		RuntimeError: 
			        An attempt has been made to start a new process before the
			        current process has finished its bootstrapping phase.
			
			        This probably means that you are not using fork to start your
			        child processes and you have forgotten to use the proper idiom
			        in the main module:
			
			            if __name__ == '__main__':
			                freeze_support()
			                ...
			
			        The "freeze_support()" line can be omitted if the program
			        is not going to be frozen to produce an executable
			總結:
		    # 1. Process(target=run_proc, args=('test',)) 用於創建一個子進程,target指定子進程中任務,args給target指定的任務傳參。
		    # 2. start()方法啓動進程
		    # 3. join()方法等待子進程結束後繼續往下運行。用於進程間同步。
		    # 4. Process(target=run_proc, args=('test',)daemon=True)
		    # daemon=True #將主線程設置爲Daemon線程,它退出時,其它子線程會同時退出,不管是否執行完任務
		    #if __name__ == '__main__':
		    #這裏的父進程指得就是我們當前程序文件,如果不加if __name__ == '__main__':
		    #則會報錯,因爲子進程在運行時是依賴於父進程的所有內容的,創建一個子進程的時候該子進程就會複製當前父進程的模塊。

進程池

		概念解釋:
		比方說一個快遞公司有五個送貨員,五個人都出去送貨了,這時又來一車貨
		這個時候怎麼辦呢,只有五個人,我們就只能等某一個送貨員送完貨回來之後
		再去送這新來的貨物,在我們進程中也是一樣,如果進程池序列中沒有可供使
		用的進程,那麼程序就會等待,直到進程池中有可用進程爲止。
		首先也要導入我們的池對象Pool
		from multiprocessing import Process,Pool   #Pool:池對象
		def python_pool(num):
		    print(pow(num,10))
		if __name__ == '__main__':
		    pool = Pool(5)
		    for i in range(5):
		        pool.apply_async(python_pool,args=(i,))   #從進程池裏取出一個進程並異步執行
		    pool.terminate()    #立刻關閉進程池
		    pool.close()   #等待所有進程結束才關閉線程池
		    pool.join()    #主進程等待所有子進程執行完畢,必須在close或terminete之後
		
		我們也可以用apply方法,那apply和apply_async到底有什麼區別呢?
			apply方法是阻塞的。
			意思就是等待當前子進程執行完畢後,在執行下一個進程。
			apply_async 是異步非阻塞的。
		    意思就是:不用等待當前進程執行完畢,隨時根據系統調度來進行進程切換。
		剛上面的代碼中用到了apply_async這個方法,註釋意思說是從進程池裏取出一個進程
		並異步執行,又介紹了apply方法,反覆提到異步同步
		這裏要給大家解釋一下同步和異步的概念:
			比方說兩個人去餐廳吃飯,我們點好餐之後坐在那裏等做好菜端上來
			這種叫做同步,點好之後我們去幹別的事情,比如去買飲料、逛街
			這種叫異步,在進程池中也是這樣的原理,同步是指一個進程在執行
			某個請求的時候,必須要到收到對方返回的信息才繼續執行下去異步
			是指進程在執行某個請求時,不管其他的進程的狀態,這個進程就
			執行後續操作;當有消息返回時系統會通知進程進行處理,這樣可以提高執行的效率
			# 總結:
		    # 1. Pool(n) 產生大小爲n的進程池。   Pool的默認大小是CPU的核數  cpu_count()
		    # 2. close()方法修改進程池狀態爲close,不允許再添加新的任務。
		    #    p.terminate()  # 殺死終止 所有的進程
		    # 3. join()方法父進程等待所有子進程執行完畢, 在join之前需調用close()方法 from multiprocessing import cpu_count
		    # 4. 使用p.apply(target=,args,kwargs)給進程池分配任務
		    # 5. p.apply_async是異步任務。python3中apply也是調用異步apply_async

線程

	 多任務可以由多進程完成,也可以由一個進程內的多線程完成。
	 剛剛我們講到線程是進程的最小執行單元,一個進程至少有一個線程。
	 Python的標準庫提供了兩個模塊:thread和threading,thread是低級模塊,
	 threading是高級模塊,對thread進行了封裝。絕大多數情況下,
	 我們只需要使用threading這個高級模塊。啓動一個線程就是把一個
	 函數傳入並創建Thread實例,然後調用start()開始執行
     def run():
	   print('主線程{},開始運行'.format(threading.current_thread().name))
	    n = 0
	    while n < 5:
	        n+=1
	        print('我是{}線程,---{}'.format(threading.current_thread().name,n))
	    print('線程{}, 結束了'.format(threading.current_thread().name))
	print('線程 %s is 運行...' % threading.current_thread().name)
	p = Thread(target=run,name='測試數據',daemon=True)
	p.start()
	p.join()
	print('線程{} 結束了'.format(threading.current_thread().name))
線程總結:
		1. threading.Thread(target,name,damemon,args,kwargs)
	       創建一個線程. target指定線程任務,name線程名,daemon爲True守護線程
	       args,kwargs 爲子線程中任務函數所需參數.
	
	    2. start()開啓線程
	    3. join()等待線程結束.
	    4. 由於任何進程默認就會啓動一個線程,我們把該線程稱爲主線程,主線程又可以啓動新的線程,
	        Python的threading模塊有個current_thread()函數,它永遠返回當前線程的實例。主線程實例的名字叫MainThread,
	        子線程的名字在創建時指定,我們用LoopThread命名子線程。名字僅僅在打印時用來顯示,完全沒有其他意義,
	        如果不起名字Python就自動給線程命名爲Thread-1,Thread-2……
	
	    5. 線程的屬性.
	        p = threading.current_thread()
	        屬性: p.name 線程名
	             p.ident 線程id
	             p.daemon 是否爲守護線程
	        方法:
	              p.getName()
	              p.is_alive()
	              p.isDaemon()
	    6. threading中有用的幾個方法
	       threading.currentThread(): 返回當前的線程變量。
	       threading.enumerate():返回一個包含正在運行的線程的list,正在運行指線程啓動後,結束前,不包括啓動前和終止後的線程。
	       threading.activeCount(): 返回正在運行的線程數量,與len(threading.enumerate())有相同的結果。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章