Python自動化開發課堂筆記【Day09】 - Python進階(異常處理,進程)

異常處理nginx

在程序運行過程當中,若是出現異常就會致使後續的程序沒法執行下去,如何保證在異常出現後經過處理保證後續代碼正常運行,
就須要用到異常處理的功能從而保證程序不會由於這些意外的錯誤而停止掉。

異常分爲兩大類:
1.由語法致使的錯誤 ---> 應該在程序運行以前就進行修正
2.邏輯上的異常 ---> try...except...程序員

NameError:使用了一個還未被賦予對象的變量
IndexError:下標索引超出序列邊界,好比當x只有三個元素,卻試圖訪問x[5]
KeyError:試圖訪問字典裏不存在的鍵
ZeroDivisionError1/0致使的錯誤
AttributeError:試圖訪問一個對象沒有的屬性
IOError:輸入/輸入異常,基本上是沒法打開文件
ImportError:沒法引入模塊或包,基本上是路徑問題或名稱錯誤
IndentationError:語法錯誤(的子類),代碼沒有正確對齊
KeyboardInterrupt:Ctrl+C被按下
SyntaxError:Python代碼非法,代碼不能編譯
TypeError:傳入的對象類型與要求不符合
UnboundLocalError:試圖訪問一個還未被設置的局部變量,基本上是因爲另有一個同名的全局變量,致使你覺得正在訪問它
ValueError:傳入一個調用者不指望的值,即便值得類型是正確的

  異常處理格式編程

try:
    須要監測的代碼段
except Exception as e: #使用Exception萬能異常,能夠免於異常的多分支處理
    異常處理代碼段
else:
    沒有異常發生時會執行的代碼
finally:
    有沒有異常都會執行的代碼段,一般會放些回收資源的代碼
其餘代碼段

操做系統json

1.什麼是操做系統:
  操做系統就是一個協調,管理和控制計算機硬件資源和軟件資源的控制程序。
2.操做系統的角色:
  操做系統位於計算機硬件與應用軟件之間,本質也是一個軟件。操做系統由操做系統的內核(運行於內核態管理硬件資源)以及
  系統調用(運行與用戶態爲應用程序員寫得應用程序提供系統調用接口)兩部分組成,因此,單純的說操做系統是運行於內核態是不許確的。
3.操做系統的功能:
  A.隱藏了醜陋的硬件調用接口,爲應用程序員提供更好更簡單更清晰的硬件資源模型,應用程序員有了這些接口後,就不用再考慮操做硬件的細節,專心開發本身的應用程序便可。
  B.將應用程序對硬件資源的靜態請求變得有序化
4.操做系統發展史:
  第一代:真空管和穿孔卡片
  第二代:晶體管和批處理系統
  第三代:集成電路芯片和多道程序設計
  第四代:我的計算機
5.多道技術:
  多道技術:內存中同時存入多道(多個)程序,CPU從一個進程快速切換到另一個,使每一個進程各自運行
  幾十或者幾百毫秒,這樣,雖然在某一個瞬間,一個CPU只能執行一個任務,但在一秒內,CPU卻能夠運行多個進程
  這就會令人產生了並行的錯覺,即僞併發,以此來區分多處理器操做系統的真正硬件並行(多個CPU共享同一個物理內存)

  多道技術中的多道指的是多個程序,多道技術的實現是爲了解決多個程序競爭或者共享同一個資源(好比CPU)
  的有序調度問題,解決方式即多路複用,多路複用分爲時間上的複用和空間上的複用。

  1.空間上的複用:將內存分爲幾部分,每一個部分放入一個程序,這樣,同一時間內存中就有了多道程序。
  2.時間上的複用:當一個程序在等待I/O時,另外一個程序可使用CPU,若是內存中能夠存放足夠多的做業,則CPU的利用率能夠接近100%。
網頁爬蟲

進程服務器

進程:正在進行的一個過程或者一個任務,負責執行任務的是CPU
程序:程序僅僅只是一堆代碼而已,而進程指的是程序的運行過程
P.S.:同一個程序執行兩次,那也是兩個進程,好比打開暴風影音,雖然都是同一個軟件,可是執行的任務卻不相同。

併發與並行
  不管是並行仍是併發,在用戶看來都是同時運行的,不論是進程仍是線程,都只是一個任務而已,真正幹活的是CPU,CPU來作這些任務,而一個CPU同一時刻只能執行一個任務。
並行:真正的同時運行,只有具有多個CPU才能實現並行
併發:是僞並行,即看起來像是同時運行。單個CPU+多道技術就能夠實現併發(並行也屬於併發)

同步和異步
  同步就是指一個進程在執行某個請求的時候,若該請求須要一段時間才能返回信息,那個這個進程將會一直等待下去,直到收到返回信息才繼續執行下去
  異步是指進程不須要一直等待下去,而是繼續執行下面的操做,無論其餘進程的狀態,當有消息返回時系統就會通知進程進行處理,這樣就能夠提升執行的效率。

進程的建立(四種形式)
  1.系統初始化
  2.一個進程在運行過程當中開啓了子進程(好比nginx開啓多進程,os.fork,subprocess.Popen等)
  3.用戶的交互形式請求,而建立一個新進程(如雙擊打開軟件)
  4.一個批處理做業的初始化(只在大型機的批處理系統中應用)

不管哪種,新進程的建立都是由一個已經存在的進程執行了一個用於建立進程的系統調用而建立的
UNIX中該系統調用的是:fork,fork會建立一個和父進程如出一轍呢的副本,兩者有相同的存儲映像,一樣的環境字符串和一樣的打開文件
Windows中該系統調用的是:CreateProcess,它既處理進程的建立,也負責把正確的程序裝入新進程

UNIX和Windows建立子進程的異同
相同點:進程建立後,父進程和子進程有各自不一樣的地址空間(多道技術要求物理層面實現進程之間內存的隔離)
    任何一個進程在其餘地址空間中的修改都不會影響到另一個進程。
不一樣點:在UNIX中,子進程的初始地址空間是父進程的一個副本,子進程和父進程是能夠有隻讀的共享內存區的。
    可是對於Windows系統來講,從一開始父進程與子進程的地址空間就是不一樣的。

進程終止的方式
  1.正常退出(自願方式,點擊exit按鈕)
  2.出錯推出(自願方式,進程運行出錯)
  3.嚴重錯誤(非自願方式,執行非法指令致使異常)
  4.被其餘進程殺死(非自願,如kill -9)

進程的層次結構
  1.在UNIX中全部進程,都是以init進程爲根,組成樹形結構。父子進程共同組成一個進程組,這樣當從鍵盤
     發出一個信號時,該信號被送給當前與鍵盤相關的進程組中全部的成員。
  2.在Windows中,沒有層次的概念,全部的進程都是地位相同的,惟一相似於進程層次的暗示,是在建立進程時,
     父進程獲得一個特別的令牌(稱爲句柄),該句柄能夠用來控制子進程,可是父進程有權把該句柄傳給其餘子進程,
  這樣就沒有層次的概念了。

進程的狀態(一個進程能夠分爲三個狀態)
  1.就緒
  2.運行
  3.阻塞
多線程

線程併發

在傳統操做系統中,每一個進程都有一個地址空間,並且默認就有一個控制線程。
多線程(即多個控制線程)的概念是,在一個進程中存在多個控制線程,多個控制線程共享該進程的地址空間。
進程只是用來把資源集中到一塊兒(進程只是一個資源單位,或者說資源集合),而線程纔是CPU上的執行單位。

多線程的優點:
  1.多線程能夠共享一個進程的地址空間
  2.線程比進程更輕量級,線程比進程更容易建立和撤銷,消耗的時間和資源更短更小,有利於大量線程快速修改
  3.對於計算機/CPU密集型應用,多線程不能提高性能,可是對於I/O密集型應用,使用多線程會明顯地提高速度
  4.在多CPU系統中,爲了最大限度利用多核,能夠開啓多個線程(比開進程開銷要小得多)app

Python併發編程值之多進程
  multiprocessing模塊用來開啓子進程,並在子進程中執行咱們定製的任務(好比函數),該模塊與多線程模塊threading的編程接口相似。
  multiprocessing模塊功能衆多:支持子進程,通訊和共享數據,執行不一樣形式的同步,提供Process,Queue,Pipe,Lock等組件dom

建立進程的兩種方式:
方式一:
from multiprocessing import Process
import time
import random
def drive(name):
    print('%s is driving' %name)
    time.sleep(random.randint(1,3))
    print('%s is an old driver' %name)
if __name__ == '__main__':
    p = Process(target=drive,args=('Albert',))
    print(p.name) #能夠經過name=來指定進程名
    print(p.pid)
    p.start()
    print('主線程/父進程')

方式二:
from multiprocessing import Process
import time
import random
class Drive(Process):
    def __init__(self,name):
        super().__init__()
        self.name = name
    def run(self):
        print('%s is driving' %self.name)
        time.sleep(random.randint(1,3))
        print('%s is an old driver' %self.name)
if __name__ == '__main__':
    p = Drive('Albert')
    p.start() #自動調用run方法
    print('主線程/父進程')

  p.join()的使用後,等到子進程所有結束以後,才能結束父進程

from multiprocessing import Process
import time
import random
def drive(name):
    print('%s is driving' %name)
    time.sleep(random.randint(1,3))
    print('%s is an old driver' %name)
if __name__ == '__main__':
    p1 = Process(target=drive,args=('Albert',))
    p2 = Process(target=drive, args=('Baker',))
    p3 = Process(target=drive, args=('Charlie',))
    P_list = [p1,p2,p3]
    for p in P_list:
        p.start()
    # p1.start()
    # p2.start()
    # p3.start()
    for p in P_list:
        p.join()
    # p1.join()
    # p2.join()
    # p3.join()
    print('主線程/父進程')

守護進程(主進程執行完子進程也會跟着被回收掉)

from multiprocessing import Process
import time
import random
def drive(name):
    print('%s is driving' %name)
    time.sleep(random.randint(1,3))
    print('%s is an old driver' %name)
if __name__ == '__main__':
    p1 = Process(target=drive,args=('Albert',))
    p1.daemon = True
    p1.start()
    print('主線程/父進程')
    
from multiprocessing import Process
import time
import random
def drive(name):
    print('%s is driving' %name)
    time.sleep(random.randint(1,3))
    print('%s is an old driver' %name)
if __name__ == '__main__':
    p1 = Process(target=drive,args=('Albert',))
    p1.start()
    p1.terminate()
    print(p1.is_alive())
    time.sleep(1)
    print(p1.is_alive())
    print('主線程/父進程')

  進程的實例應用

多進程共享一套文件系統:
from multiprocessing import Process
import time
import random
def work(filename,msg):
    with open(filename,'a',encoding='utf-8') as f:
        f.write(msg)
if __name__ == '__main__':
    for i in range(5):
        p = Process(target=work,args=('a.txt','進程%s\n' % str(i)))
        p.start()

進程的通訊方式之:隊列

from multiprocessing import Process,Queue
q = Queue(3)
q.put方法用以插入數據到隊列中,put方法還有兩個可選參數:blocked和timeout。若是blocked爲True(默認值),而且timeout爲正值,該方法會阻塞timeout指定的時間,直到該隊列有剩餘的空間。若是超時,會拋出Queue.Full異常。若是blocked爲False,但該Queue已滿,會當即拋出Queue.Full異常。
q.get方法能夠從隊列讀取而且刪除一個元素。一樣,get方法有兩個可選參數:blocked和timeout。若是blocked爲True(默認值),而且timeout爲正值,那麼在等待時間內沒有取到任何元素,會拋出Queue.Empty異常。若是blocked爲False,有兩種狀況存在,若是Queue有一個值可用,則當即返回該值,不然,若是隊列爲空,則當即拋出Queue.Empty異常.
q.get_nowait():同q.get(False)
q.put_nowait():同q.put(False)
q.empty():調用此方法時q爲空則返回True,該結果不可靠,好比在返回True的過程當中,若是隊列中又加入了項目。
q.full():調用此方法時q已滿則返回True,該結果不可靠,好比在返回True的過程當中,若是隊列中的項目被取走。
q.qsize():返回隊列中目前項目的正確數量,結果也不可靠,理由同q.empty()和q.full()同樣

生產者消費者模型
  在併發編程中使用生產者和消費者模型能解決絕大多數併發問題。該模式經過平衡生產線程和消費線程的工做能力來提升程序的總體處理的速度
爲何要使用生產者和消費者模式:
  在線程世界裏,生產者就是生產數據的線程,消費者是消費數據的線程。在多線程開發當中,若是生產者處理速度很快,
  而消費者處理速度很慢,那麼生產者就必須等待消費者處理完,才能繼續生產數據。一樣的,若是消費者的處理能力大於生產者的
  生產能力,那麼消費者就必須等待生產者。爲了解決這個問題因而引入了生產消費模型。
什麼是生產消費模型:
  生產消費模型是經過一個容器解決生產者和消費者的強耦問題。生產者和消費者彼此之間不直接通信,而經過阻塞隊列來進行
  通信,因此生產者生產完數據以後不用等待消費者處理,直接扔給阻塞隊列,消費者不找生產者要數據,而是直接從阻塞隊列裏取,
  阻塞隊列就至關於一個緩衝區,平衡了生產者和消費者的處理能力。

from multiprocessing import Process,Queue
import time
import random
def con(q,name):
    while True:
        time.sleep(random.randint(1,3))
        res = q.get()
        print('\033[41m消費者%s拿到了%s\033[0m' %(name,res))
def pro(seq,q,name):
    for item in seq:
        time.sleep(random.randint(1,3))
        q.put(item)
        print('\033[42m生產者%s生產了%s\033[0m' % (name,item))
if __name__ == '__main__':
    q = Queue()
    c = Process(target=con,args=(q,'Albert'))
    c.start()
    seq = ['包子%s' %i for i in range(10)]
    pro(seq,q,'Chef')
    
from multiprocessing import Process,JoinableQueue
import time
import random
def con(q,name):
    while True:
        time.sleep(random.randint(1,3))
        res = q.get()
        q.task_done()
        print('\033[41m消費者%s拿到了%s\033[0m' %(name,res))

def pro(seq,q,name):
    for item in seq:
        time.sleep(random.randint(1,3))
        q.put(item)
        print('\033[42m生產者%s生產了%s\033[0m' % (name,item))
    q.join()

if __name__ == '__main__':
    # q = Queue()
    q = JoinableQueue()
    c = Process(target=con,args=(q,'Albert'))
    c.daemon = True #設置守護進程,主進程結束c就結束
    c.start()

    seq = ['包子%s' %i for i in range(10)]
    p = Process(target=pro,args=(seq,q,'Chef'))
    p.start()
    p.join() #主進程等待P結束,p等待c把數據都取完,c一旦取完數據,p.join就再也不阻塞
             #進而主程序結束會回收守護進程c,並且c此時也沒有存在的必要了。
    print('主進程')

進程同步(模擬搶票)

from multiprocessing import Process, Lock
import json
import time
import random
def work(dbfile,name,lock):
    lock.acquire()
    with open(dbfile,'r', encoding='utf-8') as f:
        dic = json.loads(f.read())
    if dic['count'] > 0:
        dic['count'] -= 1
        time.sleep(random.randint(1,3))
        with open(dbfile,'w',encoding='utf-8') as f:
            f.write(json.dumps(dic))
        print('\033[43m%s搶票成功\033[0m' % name)
    else:
        print('\033[45m%s搶票失敗\033[0m' % name)
    lock.release()

if __name__ == '__main__':
    lock = Lock()
    p_list = []
    for i in range(50):
        p = Process(target=work,args=('a.txt',i,lock))
        p_list.append(p)
        p.start()

    for p in p_list:
        p.join()

    print('主進程')

進程池(模擬服務器和多客戶端通訊)

服務端

from multiprocessing import Process, Pool
from socket import *
server = socket(AF_INET,SOCK_STREAM)
server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
server.bind(('127.0.0.1',8080))
server.listen(5)

def talk(conn,addr):#通信鏈接
    print('conn=',conn)
    print('addr=',addr)
    while True:
        try:
            msg = conn.recv(1024)
            o_msg = msg.decode()
            print('%s:%s' %(addr,o_msg))
            if not msg: break
            conn.send(msg.upper())
        except Exception:
            break
if __name__ == '__main__':
    pool = Pool()
    while True:  # 鏈接循環
        conn, addr = server.accept()
        # pool.apply(talk,(conn,addr)) #同步執行
        res = pool.apply_async(talk,(conn,addr))
        # p = Process(target=talk, args=(conn, addr,))
        # p.start()
客服端

from socket import *
client = socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8080))

while True:
    msg = input('>>>:').strip()
    if not msg:continue
    client.send(msg.encode('utf-8'))
    msg = client.recv(1024)
    print(msg.decode('utf-8'))

進程池之回調函數

from multiprocessing import Pool,Process
import os
def work(i):
    return i**2

if __name__ == '__main__':
    pool = Pool()
    res_list = []
    for i in range(6):
        res = pool.apply_async(work,args=(i,))
        res_list.append(res)
    for res in res_list:
        print(res.get())

  回調函數應用之:網頁爬蟲

from multiprocessing import Pool
import time,random
import requests
import re

def get_page(url,pattern):
    response=requests.get(url)
    if response.status_code == 200:
        return (response.text,pattern)

def parse_page(info):
    print('parse_page')
    page_content,pattern=info
    res=re.findall(pattern,page_content)
    for item in res:
        dic={
            'index':item[0],
            'title':item[1],
            'actor':item[2].strip()[3:],
            'time':item[3][5:],
            'score':item[4]+item[5]

        }
        print(dic)
if __name__ == '__main__':
    pattern1=re.compile(r'<dd>.*?board-index.*?>(\d+)<.*?title="(.*?)".*?star.*?>(.*?)<.*?releasetime.*?>(.*?)<.*?integer.*?>(.*?)<.*?fraction.*?>(.*?)<',re.S)

    url_dic={
        'http://maoyan.com/board/7':pattern1,
    }

    p=Pool()
    res_l=[]
    for url,pattern in url_dic.items():
        res=p.apply_async(get_page,args=(url,pattern),callback=parse_page)
        res_l.append(res)

    for i in res_l:
        i.get()

 

士大夫

相關文章
相關標籤/搜索