day33 網絡編程之線程,並發
阿新 • • 發佈:2017-12-05
編程 mit running rt thread 版本 [] .com print 文本操作
概要:
1 並發編程需要掌握的知識點: 2 開啟進程/線程 3 生產者消費者模型!!! 4 GIL全局解釋器鎖(進程與線程的區別和應用場景) 5 進程池線程池 6 7 IO模型(理論) 8 9 10 1 多線程 11 線程的概念? 12 一個進程內默認就會有一個控制線程,該控制線程可以執行代碼從而創建新的線程 13 該控制線程的執行周期就代表改進程的執行周期 14 線程VS進程 15 1、線程的創建開銷小於進程,創建速度快 16 2、同一進程下的多個線程共享該進程的地址空間View Code17 GIL全局解釋器鎖 18 線程池
開啟線程的兩種方式:
from threading import Thread from multiprocessing import Process import time,os def task(): print(‘%s is running‘ % os.getpid()) time.sleep(5) print(‘%s is done‘ % os.getpid()) class Mythread(Thread): def __init__(self, name): super().View Code__init__() self.name=name def run(self): print(‘%s is running‘ % os.getpid()) time.sleep(5) print(‘%s is done‘ % os.getpid()) if __name__ == ‘__main__‘: # t=Thread(target=task,) # t=Process(target=task,) t=Mythread(‘xxxxx‘) t.start() print(‘主‘) ‘‘‘ 1、一個進程內不開子進程也不開“子線程”:主線程結束,該進程就結束 2、當一個進程內開啟子進程時: 主線程結束,主進程要等,等所有子進程運行完畢,給兒子收屍 3、當一個進程內開啟多個線程時: 主線程結束並不意味著進程結束, 進程的結束指的是該進程內所有的線程都運行完畢,才應該回收進程 ‘‘‘
這裏需要註意一下,在線程裏不存在僵屍線程和孤兒線程的概念.
進程和線程的區別:
#瞅一眼:PPID,PID from threading import Thread from multiprocessing import Process import time,os def task(): print(‘partent:%s self:%s‘ %(os.getppid(),os.getpid())) time.sleep(5) if __name__ == ‘__main__‘: t=Thread(target=task,) # t=Process(target=task,) t.start() print(‘主‘,os.getppid(),os.getpid()) #進程直接內存空間隔離 from threading import Thread from multiprocessing import Process import time,os n=100 def task(): global n n=0 if __name__ == ‘__main__‘: t=Process(target=task,) t.start() t.join() print(‘主‘,n) #線程之間內存空間共享 from threading import Thread import time,os n=100 def task(): global n n=0 if __name__ == ‘__main__‘: t=Thread(target=task,) t.start() t.join() print(‘主‘,n)View Code
線程的其他屬性以及方法:
from threading import Thread,current_thread,enumerate,active_count import time,os def task(): print(‘%s is running‘ %current_thread().getName()) time.sleep(5) print(‘%s is done‘ %current_thread().getName()) if __name__ == ‘__main__‘: # t=Thread(target=task,name=‘xxxx‘) # # 這裏有其他的參數就接著往後傳即可,沒有就只寫一個函數名 t=Thread(target=task) t.start() # print(t.name) #查看當前活著的線程 print(enumerate()[0].getName()) # # MainThread print(enumerate()[1].getName())------Thread-1 # 這裏有兩個進程所以索引值就是只有0,1,超出部分會報錯,out of range print(active_count()) print(‘主‘,current_thread().getName()) # # 主 MainThreadView Code
線程池:
from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor from threading import current_thread import time,random def task(n): print(‘%s is running‘ %current_thread().getName()) time.sleep(random.randint(1,3)) return n**2 if __name__ == ‘__main__‘: # t=ProcessPoolExecutor() #默認是cpu的核數 # import os # print(os.cpu_count()) t=ThreadPoolExecutor(3) #默認是cpu的核數*5 objs=[] for i in range(10): obj=t.submit(task,i) objs.append(obj) t.shutdown(wait=True) for obj in objs: print(obj.result()) print(‘主‘,current_thread().getName())View Code
這裏有線程池的作業,我一並粘過來:
# 默寫的內容是爬蟲線程池的回調機制的代碼 # socket 套接字用線程池的方式去寫,然後再用多線程的方式去寫 # 文本處理工具的三個任務先把一個套接字寫出來然後看看怎麽改成線程的概念 ‘‘‘ 以下則是開啟多線程的方式: from socket import * from multiprocessing import Process from threading import Thread ser = socket(AF_INET, SOCK_DGRAM) ser.bind((‘127.0.0.1‘, 3020)) ser.listen(2) def connunicate(conn): while True: data = conn.recv() conn.send(data.upper()) if __name__ == ‘__main__‘: while True: conn, addr = ser.accept() t = Thread(target=connunicate, args=conn) t.start() ‘‘‘ ‘‘‘ from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor from threading import current_thread import os def task(n): print(‘%s is running‘ % current_thread().getName()) if __name__ == ‘__main__‘: t = ThreadProcessExecutor(12) # t = ProcessPoolExecutor(4) objs = [] for i in range(20): obj = t.submit(task, i) objs.append(obj) t.shutdown(wait=True) for obj in objs: print(obj.result()) print(‘主‘, os.getpid(), current_thread().getName()) ‘‘‘ # 線程池的版本要理解後背下來!***** # 開啟線程池的方式: 這裏是中級版本,已經搞定,功能都實現了,想要的結果都得到了! from socket import * from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor from threading import current_thread import os server = socket(AF_INET, SOCK_STREAM) server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) server.bind((‘127.0.0.1‘, 5038)) server.listen(3) def connunicate(conn,num): while True: data = conn.recv(1024) conn.send([data.upper(), os.getpid()]) print(os.getpid()) conn.close() if __name__ == ‘__main__‘: t = ThreadPoolExecutor(12) objs = [] while True: conn, addr = server.accept() tt = t.submit(connunicate, conn, os.getpid()) objs.append(tt) # t.shutdown(wait=True) for ob in objs: print(ob.result()) print(‘主‘, os.getpid()) # 客戶端版本如下: from socket import * client=socket(AF_INET,SOCK_STREAM) client.connect((‘127.0.0.1‘, 5038)) while True: msg=input(‘>>: ‘).strip() if not msg:continue client.send(msg.encode(‘utf-8‘)) data=client.recv(1024) print(data.decode(‘utf-8‘))View Code
以上的有需要補充的,那個文本操作沒有寫出來,把老師博客裏面的代碼粘過來,
from threading import Thread msg_l=[] format_l=[] def talk(): while True: msg=input(‘>>: ‘).strip() if not msg:continue msg_l.append(msg) def format_msg(): while True: if msg_l: res=msg_l.pop() format_l.append(res.upper()) def save(): while True: if format_l: with open(‘db.txt‘,‘a‘,encoding=‘utf-8‘) as f: res=format_l.pop() f.write(‘%s\n‘ %res) if __name__ == ‘__main__‘: t1=Thread(target=talk) t2=Thread(target=format_msg) t3=Thread(target=save) t1.start() t2.start() t3.start()View Code
其實也好理解,就是自己沒有多想一想,過早的放棄了.
異步概念補充(含回調函數):
# #pip install requests # import requests # from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor # from threading import current_thread # import time # import os # # def get(url): # print(‘%s GET %s‘ %(os.getpid(),url)) # response=requests.get(url) # time.sleep(3) # if response.status_code == 200: # return {‘url‘:url,‘text‘:response.text} # # def parse(obj): # res=obj.result() # print(‘[%s] <%s> (%s)‘ % (os.getpid(), res[‘url‘],len(res[‘text‘]))) # # if __name__ == ‘__main__‘: # urls = [ # ‘https://www.python.org‘, # ‘https://www.baidu.com‘, # ‘https://www.jd.com‘, # ‘https://www.tmall.com‘, # ] # # t=ThreadPoolExecutor(2) # t=ProcessPoolExecutor(2) # for url in urls: # t.submit(get,url).add_done_callback(parse) # t.shutdown(wait=True) # # print(‘主‘,os.getpid()) # ‘‘‘ # 異步調用: # 提交完任務(為該任務綁定一個回調函數),不用再原地等任務執行完畢拿到結果,可以直接提交下一個任務 # 一個任務一旦執行完畢就會自動觸發回調函數的運行 # # 回調函數的參數是單一的: # 回調函數的參數就是它所綁定任務的返回值 # # ‘‘‘ #pip install requests import requests from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor from threading import current_thread import time import os def get(url): print(‘%s GET %s‘ %(current_thread().getName(),url)) response=requests.get(url) time.sleep(3) if response.status_code == 200: return {‘url‘:url,‘text‘:response.text} def parse(obj): res=obj.result() print(‘[%s] <%s> (%s)‘ % (current_thread().getName(), res[‘url‘],len(res[‘text‘]))) if __name__ == ‘__main__‘: urls = [ ‘https://www.python.org‘, ‘https://www.baidu.com‘, ‘https://www.jd.com‘, ‘https://www.tmall.com‘, ] t=ThreadPoolExecutor(2) for url in urls: t.submit(get,url).add_done_callback(parse) t.shutdown(wait=True) print(‘主‘,os.getpid())View Code
這裏的異步概念是,默寫的內容,已經默出來過的.
day33 網絡編程之線程,並發