11月python學習

11月學習總結

單例模式

  • 只能建立一個對象
# 單例模式
class A:
    __isinstace = None

    def __init__(self):
        print('init')

    # __new__方法是爲對象在內存中開闢內存空間,__init__是爲該空間封裝屬性
    def __new__(cls, *args, **kwargs):
      print('new')
        if not cls.__isinstace:
            cls.__isinstace = super().__new__(cls)
        return cls.__isinstace


if __name__ == '__main__':
    a = A()
    aa = A()

    print(id(a))
    print(id(aa))

item系列

  • item的全部方法是以訪問字典的方式訪問對象的全部屬性
  • attr的全部方法是以操做變量的方法操做對象的內部屬性
  • 對於訪問、更新、建立、刪除不存在的屬性時會調用attr相關的方法
class A:
    def __init__(self, v):
        self.v = v

    def __getitem__(self, key):
        print('getitem')

    def __setitem__(self, key, value):
        print('setitem')

    def __getattr__(self, key):
        print('getattr')

    def __setattr__(self, key, value):
        print('setattr')

    def __delitem__(self, key):
        print('delitem')

    def __delattr__(self, key):
        print('delattr')

if __name__ == '__main__':
    a = A(1)
    a['v'] = 1
    a.v = 2

    v = a.v
    vv = a['v']

    del a.v
    del a['v']

上下文管理

class A:
    def __init__(self):
        print('init')

    def __enter__(self):
        print('enter')
        return 1

    def __exit__(self, exception_type, exception_value, traceback):
        print('exit')


if __name__ == '__main__':
    # a 爲__enter__方法返回的值
    with A() as a:
        print(a)

反射

首先獲取目標的全部方法、屬性集,而後再獲取。python

attr()方法就是經過參數獲取相應對象中的值。編程

其中一個很重要的功能就是hasattr()和getattr(),由於python一切皆對象,因此說全部的屬性和方法是以字典的形式保存的,即key-->value,鍵名對應着值。若要獲取一個對象的屬性的值,就是前往該對象的屬性、方法集合中去尋找相應的鍵,若存在就返回值,不然就報錯,若調用getattr就會作相應的錯誤處理(返回一句提示);若要更新一個對象中的值,則是前往屬性、方法集合中去尋找相應的鍵,並更新值,若鍵不存在就更新集合,添加一個鍵,並默認爲其賦予默認的值。緩存

class A:
    def __init__(self, value):
        self.value = value



if __name__ == '__main__':
    a = A(1)
    if hasattr(a, 'b'):
        getattr(a, 'b')
    else:
        print('not find')

    print(getattr(a, 'b', 'not find'))


def func1():
    print('func1')

def fun2():
    print('func2')


# globals()獲取當前文件中全部的方法和屬性
# print(globals()['func1']())


import sys

# 獲取當前主進程模塊
obj = sys.modules['__main__']
print(obj.__dict__)

多進程

  • 單繼承
    • 建立方法
      • 建立Process對象
      • 繼承Process對象
        • 重寫run方法,至關因而target的值,能夠經過實現__init__,經過super().__init__()實現傳入參數
  • 多進程
    • 建立
      • 多進程
        • 屢次建立對象
      • 進程池
        • 列表存儲
        • Pool對象存儲
    • 進程間的通訊
      • Queue是位於內存中的一個交換的之間的區域,用於存放兩個進程之間須要公用的數據。
      • 進程池
        • Manager().Queue()
      • Queue()(使用方法與進程池的Queue相似,傳入一個數據表示一次性最多能夠緩存的消息數量)
      • 通常的鎖
      • 死鎖(各持一把對方都須要的鎖)

python中因爲GIL(全局解釋鎖)的存在,一次只能執行一個進程,並不能達到真正意義上的多進程安全

# 多進程
from multiprocessing import Process, Pool,Manager, Lock
import time

def func1():
    print('fucn1')

def func2():
    print('func2')


def func3(i):
    print('接收', i)
    time.sleep(1)
    print('結束', i)


def func3(queue, i, lock):
    lock.acquire()
    queue.put(f'放入{i}')
    print(f'成功放入{i}')
    time.sleep(2)
    lock.release()

def func4(queue):
    data = queue.get()
    print('拿出數據:', data)
    time.sleep(0.5)

class MyProcess(Process):
    def __init__(self, args):
        self.args = args
        super().__init__(target=self.run, args=args)
    def run(self):
        print('獲取', self.args[0])
        time.sleep(1)
        print('結束', self.args[0])


if __name__ == '__main__':
    # p1 = Process(target=func1)
    # p2 = Process(target=func2)
    start = time.time()

    # 進程池
    # processes = [Process(target=func3, args=(i, )) for i in range(100)]

    # pool = Pool()
    # for i in range(100):
    #     pool.apply_async(func3, (i,))
    #
    # pool.close()
    # pool.join()

    # for p in processes:
    #     p.start()
    #
    # for p in processes:
    #     p.join()
    # p1.start()
    # p2.start()
    #
    # p1.join()
    # p2.join()

    # 繼承實現
    # processes = [MyProcess(args=(i,)) for i in range(100)]
    # for p in processes:
    #     p.start()
    # for p in processes:
    #     p.join()


    # 進程間通訊
    queue = Manager().Queue()
    lock = Lock()


    processes = [Process(target=func3, args=(queue, i, lock)) for i in range(50)]

    processes += [Process(target=func4, args=(queue,)) for _ in range(40)]

    for p in processes:
            p.start()

    for p in processes:
            p.join()

    # 鎖


    end = time.time()
    print('主進程結束, 耗時:', end-start)

多線程

  • 進程是計算機分配資源的基本單位,線程是計算機執行的基本單位。
  • 線程必須存在於進程中。
  • 計算密集型任務用進程,I/O密集型用線程。
  • 線程的建立與進程的建立十分相似。
  • 線程的五種狀態:
    • 建立
    • 就緒
    • 運行
    • 阻塞/睡眠/掛起
    • 死亡
# 多線程
from threading import Thread
import time
a = 0
def fun1():
    print('func1')

def fun2():
    print('func2')

def fun3():
    global a
    print('計算開始:', a)
    for i in range(1000000):
        a += 1
    print('計算結束:', a)

def func4():
    global a
    print('計算開始', a)
    for i in range(100000):
        a -= 1
    print('計算結果', a)
class MyThread(Thread):
    def run(self):
        print('MyThread')
        time.sleep(1)

if __name__ == '__main__':

    start = time.time()

    # 單線程
    # t1 = Thread(target=fun1)
    # t2 = Thread(target=fun2)
    #
    # t1.start()
    # t2.start()
    #
    # t1.join()
    # t2.join()

    # 多線程

    # threads = [MyThread() for _ in range(100)]
    #
    # for t in threads:
    #     t.start()
    # for t in threads:
    #     t.join()

    # 多線程通訊, 以及多線程之間的併發所形成的數據有誤

    threads = [Thread(target=fun3) for _ in range(100)]
    # threads += [Thread(target=func4) for _ in range(100)]




    for t in threads:
        t.start()

    for t in threads:
        t.join()

    end = time.time()

    print('最終結果:',a)
    print('耗時:', end-start)

信號量semaphore

表示同一時間內最多幾個線程爲就緒狀態,準備被系統調度運行。服務器

from threading import Thread, Semaphore
import time

def func1(i):
    s.acquire()
    print(f'開始執行{i}')
    time.sleep(1)
    print(f'結束行執行{i}')
    s.release()

if __name__ == "__main__":  

    start = time.time()  
    s = Semaphore(5)
    threads = [Thread(target=func1, args=(i, )) for i in range(100)]
    for t in threads:
        t.start()
    for i in threads:
        t.join()

    end = time.time()

    print('執行完成,耗時',end - start)

python程序的執行過程

  • 當執行python程序時,操做系統將程序和pythpn解釋器加載到內存中,並開闢一塊空間用於執行程序
  • python解釋器分爲編譯器和虛擬機,首先編譯器將python編譯成C程序,而後虛擬機將C程序轉換成字節碼,而後輸出機器碼

同步鎖

按照指定順序執行程序即爲同步,不然就爲異步。網絡

from threading import Thread, Lock
import time

def func1():
    while True:
        lock1.acquire()
        print('func1')
        time.sleep(0.5)
        lock2.release()


def func2():
    while True:
        lock2.acquire()
        print('func2')
        time.sleep(0.5)
        lock3.release()


def func3():
    while True:
        lock3.acquire()
        print('func3')
        time.sleep(0.5)
        lock1.release()


if __name__ == "__main__":

    lock1 = Lock()
    lock2 = Lock()
    lock2.acquire()
    lock3 = Lock()
    lock3.acquire()

    t1 = Thread(target=func1)

    t2 = Thread(target=func2)

    t3 = Thread(target=func3)

    t1.start()
    t2.start()
    t3.start()

網絡編程

  • 一對一
    • tcp 安全,速率較慢
    • udp 快速,每次都是發送的數據包, 易數據丟失
    • tcp & udp
      • 面向鏈接和不面向鏈接
      • 佔用系統資源
      • 數據流與數據報
      • tcp穩定,保證順序性, udp可能丟包, 不保證順序性
      • tcp --> send()/recv(), udp--> sendto(data, addr)/recvfrom()
  • 3次握手
    • 在tcp時,當執行connect()時,就會發生,首先客戶端向服務端發送鏈接請求,服務段返回確認碼atk和syn碼,表示接收到請求,並告知客戶端,客戶端收到後返回確認碼atk。
  • 4次揮手
    • 在tcp中,當執行close()時,如果客戶端,則向服務端發送斷開鏈接請求,服務端收到後響應,返回確認碼,而後,服務端再發送消息告知客戶端將要斷開鏈接,客戶端迴應。
  • 全雙工聊天室
    • 一對一
    • 一對多

通常步驟

  1. 導包
  2. 建立套接字
  3. 綁定地址和端口
  4. 監聽/發送消息
  5. 關閉套接字

在OSI7層模型的4層模型中,應用層一下的都是由socket封裝。多線程

一對一

TCP

# tcp 服務端
from socket import *

# tcp
s = socket(AF_INET, SOCK_STREAM)
s.bind(('localhost', 9999))

s.listen()


new_socket = s.accept() # 返回的是一個套接字和客戶端的ip+端口號
# socket, addr = new_socket
print(new_socket)
data = new_socket[0].recv(1024)
# socket.send(message.encode('utf-8'))
print(data[1][0])

if len(data) == 0: # 當客戶端斷開鏈接時會發送一個長度爲0的數據,當檢測到長度爲0時,說明客戶端已經斷開鏈接p
    new_socket[0].close()

s.close()


# 客戶端
from socket import *

s = socket(AF_INET, SOCK_STREAM)

s.connect(('localhost', 9999))
# 客戶端請求鏈接,鏈接成功後就能夠收發消息了
s.send('hhhhh'.encode('utf-8'))
s.recv(1024)
s.close()

UDP

# 服務端
from socket import *

s = socket(AF_INET, SOCK_DGRAM)

s.bind(('localhost', 9999))

data = s.recvfrom(1024)

print(data)

s.close()

# 客戶端

s = socket(AF_INET, SOCK_DGRAM)

s.sendto('hhhh'.encode('utf-8'), ('localhost', 9999))

s.close()

全雙工聊天室

一對一

from socket import *
from threading import Thread
import time

# 客戶端/服務端(udp) 
class Send(Thread):
    def run(self):
        while True:
            data = input('>>>')
            s.sendto(data.encode('utf-8'), addr)
            time.sleep(0.5)

class Receive(Thread):
    def run(self):
        while True:
            data = s.recvfrom(1024)
            print(data[0].decode('utf-8'))
            time.sleep(0.5)
 

if __name__ =='__main__':

    s = socket(AF_INET, SOCK_DGRAM)

    addr = ('localhost', 9999)
    s.bind(('localhost', 8888))

    send = Send()
    rece = Receive()

    try:
        send.start()
        rece.start()
        send.join()
        rece.join()
    finally:
        s.close()

併發服務器

線程實現併發

from socket import *
from threading import Thread
import time

def deal_with_client(socket, addr):
    while True:
        data = socket.recv(1024)
        if len(data) == 0:
            break
        print(data.decode('utf-8'))
        time.sleep(0.5)
    socket.close()

if __name__ == '__main__':

    s = socket(AF_INET, SOCK_STREAM)
    s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) # 通常來講一個線程佔用一個端口,經過設置這個使得多個線程能夠訪問同一個端口
    s.bind(('localhost', 8888))
    s.listen()
    while True:
        new_socket, new_addr = s.accept()
        p = Thread(target=deal_with_client, args=(new_socket, new_addr))  
        p.start()  
    s.close()
相關文章
相關標籤/搜索