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)
反射
首先获取目标的所有方法、属性集,然后再获取。
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()时,若是客户端,则向服务端发送断开连接请求,服务端收到后响应,返回确认码,然后,服务端再发送消息告知客户端将要断开连接,客户端回应。
- 全双工聊天室
- 一对一
- 一对多
一般步骤
- 导包
- 创建套接字
- 绑定地址和端口
- 监听/发送消息
- 关闭套接字
在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()