1.IO概述

input 和 output: 是在内存中存在的数据交换操作

内存和磁盘交换: 文件读写, 打印

内存和网络交换: recv send recvfrom, sendto

IO密集型程序: 程序中执行大量的IO操作,而较少的需要CPU运行,消耗CPU资源少,运行周期往往比较长

CPU密集型程序: 程序中执行大量的CPU运算,而较少的需要IO操作,消耗CPU资源多

2.IO分类(阻塞/非阻塞)

阻塞IO: 默认形态,是效率最低的一种IO
        1.因为等待某种条件达成再继续运行,例如: accept recv input

        2.处理IO事件时耗时较长也会产生阻塞,例如: 文件的读写过程,网络数据的传输过程

非阻塞IO: 通过修改IO对象使其变为非阻塞状态,通常用循环来不断判断阻塞条件,需要消耗更多的CPU但是在一定程度上提高了IO效率

IO多路复用: 通过同时监控多个IO事件,当那个IO事件就绪就执行那个IO事件,形成并发效果,也被称作事件驱动IO

信号驱动IO: 准备数据阶段(用户进程非阻塞),复制数据阶段(用户进程阻塞)

        1.当调用read函数的时候,准备数据的过程中用户线程不阻塞,用户线程可以去做其他事情

        2.等到数据准备完了,用户进程会收到一个SIGIO信号,然后可以在信号处理函数中处理数据

异步IO: Python实现不了,但是tornado框架自带异步IO

        1.阻塞IO,非阻塞IO,多路复用IO,信号驱动IO都是同步IO,都需等待将数据从内核缓冲区拷贝到用户内存,会阻塞进程

        2.异步IO是异步IO,当用户发起一个操作后就立即去做其他事情了,内核会等待,检测数据直到数据准备完成

        3.然后将数据拷贝到用户内存(无需先拷贝到内核缓冲区),这一切完成后会给用户进程发送一个信号告知操作完成了

3.非阻塞IO-效率比阻塞IO高

1.非阻塞IO设置方法

import socket

s = socket.socket()  # 默认会创建流式套接字

# 修改套接字设置的阻塞状态
# 参数(bool类型): 默认为True,设置为False则为非阻塞
s.setblocking()

2.TCP服务端-非阻塞IO

import socket
import time def main():
# 创建数据流套接字
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口重用
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 绑定端口,运行局域网内的客户端连接
tcp_server_socket.bind(("0.0.0.0", 7890))
# 让默认的套接字由主动变为被动监听 listen
tcp_server_socket.listen(128)
# 设置套接字为非阻塞状态
tcp_server_socket.setblocking(False) # 循环目的: 多次调用accept等待客户端连接,为多个客服端服务
while True:
print("等待一个新的客户端的到来...")
try:
new_client_socket, client_addr = tcp_server_socket.accept()
except BlockingIOError:
time.sleep(1)
print(time.ctime())
continue
print("客户端' %s '已经到来" % str(client_addr)) # 设置客户端字为非阻塞状态
new_client_socket.setblocking(False) # 循环目的: 为同一个客服端服务多次
while True:
try:
# 接收客户端发送过来的请求
recv_data = new_client_socket.recv(1024)
# recv解堵塞的两种方式: 1.客户端发送过来数据,2.客户端调用了close
if recv_data:
print("客户端' %s '发送过来的请求是: %s" % (str(client_addr), recv_data.decode("utf-8")))
# 回送数据给客户端表示响应客户端的请求
send_data = "----ok----Request accepted"
new_client_socket.send(send_data.encode("utf-8"))
else:
break
except BlockingIOError:
time.sleep(1)
print(time.time())
continue # 关闭accept返回的套接字
new_client_socket.close()
print("已经为 %s 客户端已经服务完毕" % str(client_addr))
# 关闭监听套接字
tcp_server_socket.close() if __name__ == "__main__":
main()

3.TCP客户端-非阻塞IO

import socket

def main():
# 创建数据流套接字
tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接服务器
server_ip = input("请输入要连接的服务器的ip:")
serve_port = int(input("请输入要连接的服务器的port:"))
server_addr = (server_ip, serve_port)
tcp_client_socket.connect(server_addr)
# 发送数据
send_data = input("请输入要发生的数据:")
tcp_client_socket.send(send_data.encode("utf-8"))
# 接收服务器发送过来的数据
recv_data = tcp_client_socket.recv(1024)
print("接收到的数据为:%s" % recv_data.decode("utf-8"))
# 关闭套接字
tcp_client_socket.close() if __name__ == "__main__":
main()

4.超时检测(超时等待)-效率比非阻塞IO高

1.超时检测设置

import socket

s = socket.socket()  # 默认会创建流式套接字

# 设置套接字的超时检测,所谓的超时检测即对原本阻塞的函数进行设置,使其不再始终阻塞,而是阻塞等待一定时间后自动返回
# 参数: 超时时间,在规定时间中如果正常接收阻塞则继续执行否则产生timeout异常
s.settimeout(5) # 设置超时时间为5秒

2.TCP服务端-超时检测

import socket
import traceback def main():
# 创建数据流套接字
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口重用
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 绑定端口,运行局域网内的客户端连接
tcp_server_socket.bind(("0.0.0.0", 7890))
# 让默认的套接字由主动变为被动监听 listen
tcp_server_socket.listen(128)
# 设置套接字超时等待时间为5秒
tcp_server_socket.settimeout(5) # 循环目的: 多次调用accept等待客户端连接,为多个客服端服务
while True:
print("等待一个新的客户端的到来...")
try:
new_client_socket, client_addr = tcp_server_socket.accept()
except Exception:
traceback.print_exc()
continue
print("客户端' %s '已经到来" % str(client_addr)) # 设置客户端字的超时等待时间为5秒
new_client_socket.settimeout(5) # 循环目的: 为同一个客服端服务多次
while True:
try:
# 接收客户端发送过来的请求
recv_data = new_client_socket.recv(1024)
# recv解堵塞的两种方式: 1.客户端发送过来数据,2.客户端调用了close
if recv_data:
print("客户端' %s '发送过来的请求是: %s" % (str(client_addr), recv_data.decode("utf-8")))
# 回送数据给客户端表示响应客户端的请求
send_data = "----ok----Request accepted"
new_client_socket.send(send_data.encode("utf-8"))
else:
break
except Exception:
traceback.print_exc()
continue # 关闭accept返回的套接字
new_client_socket.close()
print("已经为 %s 客户端已经服务完毕" % str(client_addr))
# 关闭监听套接字
tcp_server_socket.close() if __name__ == "__main__":
main()

3.TCP客户端-超时检测

import socket

def main():
# 创建数据流套接字
tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接服务器
server_ip = input("请输入要连接的服务器的ip:")
serve_port = int(input("请输入要连接的服务器的port:"))
server_addr = (server_ip, serve_port)
tcp_client_socket.connect(server_addr)
# 发送数据
send_data = input("请输入要发生的数据:")
tcp_client_socket.send(send_data.encode("utf-8"))
# 接收服务器发送过来的数据
recv_data = tcp_client_socket.recv(1024)
print("接收到的数据为:%s" % recv_data.decode("utf-8"))
# 关闭套接字
tcp_client_socket.close() if __name__ == "__main__":
main()

5.IO多路复用-效率比超时等待高

1.IO多路复用概述

1.IO多路复用的定义: 同时监控多个IO事件,当那个IO事件就绪就执行那个IO事件,形成并发效果

2.使用IO多路复用的注意点
            1.在处理IO过程中不应该发生死循环(即某个IO单独占用服务器)

            2.IO多路复用是单进程程序,是一个并发程序

            3.IO多路复用有较高的IO执行效率

2.IO多路复用-select模块中的三个方法(select,pool,epool)

1.三个方法的适用平台

            select: 适用于Windows Linux Unix MacOS

            poll: 适用于Linux Unix MacOS

            epoll: 适用于Linux Unix

2.select方法-采用轮询机制,32位机文件描述符只能开1024,64位机文件描述符只能开2048

            r,w,x = select(rlist, wlist, xlist, [timeout])

                功能: 监控IO事件,阻塞等待IO事件发生

                参数:

                    rlist: 列表,存放要监控等待处理的IO,例如客户端主动连接,或客户端发送消息

                    wlist: 列表,存放希望主动处理的IO,例如回送消息给客户端

                    xlist: 列表,存放如果发生异常需要处理的IO

                    timeout: 数字,超时检测,默认一直阻塞

                返回值:

                    r: 列表,rlist中准备就绪的IO

                    w: 列表,wlist中准备就绪的IO

                    x: 列表,xlist中准备就绪的IO

3.poll方法-采用轮询机制突破了文件描述符只能开1024的限制(1G内存大概能开10万个事件去监听),效率上和select差不多

            1.创建poll对象

                p = select.poll()

            2.加入关注的IO

                p.register(s)  # 添加IO关注

                p.unregister(s)  # 从关注IO中删除

            3.使用poll函数监控

                events = p.poll()

                功能: 阻塞等待register的事件只要有任意准备就绪即返回

                返回值: events  # [(fileno, event), (), ()]; fileno: 文件描述符; event: 准备就绪的事件

            4.处理发生的IO事件

                # poll的IO事件

                POLLIN  # 可读rlist

                POLLOUT  # 可写wlist

                POLLUP  # 断开连接

                POLLERR  # 异常xlist

                POLLPRI  # 紧急处理

                POLLVAL  # 无效数据

4.epoll方法: 采用了回调机制同样也突破了文件描述符只能开1024的限制(1G内存大概能开10万个事件去监听)

            1.效率上比poll和select稍高,但只能用于Linux和Unix平台

            2.epoll既可以采用水平触发,也可以采用边缘触发,而select和pool只支持水平触发

            3.epoll实现原理提流程图: https://www.processon.com/view/link/5efd699c7d9c08442043e5b8

            4.水平触发: 如果文件描述符已经就绪可以非阻塞的执行IO操作了,此时会触发通知,允许在任意时刻重复检测IO的状态,

                没有必要每次描述符就绪后尽可能多的执行IO,select和pool就属于水平触发

            5.边缘触发: 如果文件描述符自上次状态改变后有新的IO活动到来,此时会触发通知,在收到一个IO事件通知后要尽可能多的执行IO操作,

                因为如果在一次通知中没有执行完IO那么就需要等到下一次新的IO活动到来才能获取到就绪的描述符,信号驱动式IO就属于边缘触发

3.TCP服务端-select方法实现IO多路复用

import socket
import sys
import traceback
import select def main():
# 创建数据流套接字
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口重用
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 绑定端口,运行局域网内的客户端连接
tcp_server_socket.bind(("0.0.0.0", 7890))
# 让默认的套接字由主动变为被动监听 listen
tcp_server_socket.listen(128)
# 设置套接字超时等待时间为5秒
tcp_server_socket.settimeout(5) # 创建一个列表存放要监控等待处理的IO
rlist = [tcp_server_socket]
# 创建一个列表存放希望主动处理的IO
wlist = list()
# 创建一个列表存放如果发生异常需要处理的IO
xlist = [tcp_server_socket] # 循环目的: 多次调用select监控客户端连接事件,阻塞等待客户端连接事件发生
while True:
print("监控是否有新的客户端的到来...")
# 参数说明: rlist: 列表,存放要监控等待处理的IO; wlist: 列表,存放希望主动处理的IO
# 参数说明: xlist: 列表,存放如果发生异常需要处理的IO; timeout: 数字,超时检测,默认一直阻塞
# 返回值说明: rs: 列表,rlist中准备就绪的IO; ws: 列表,wlist中准备就绪的IO; xs: 列表,xlist中准备就绪的IO
# wlist有内容,select会解除阻塞立即返回
rs, ws, xs = select.select(rlist, wlist, xlist, 5) # 设置超时等待时间为5秒 # 遍历准备就绪的IO列表
for r in rs:
# 有客户端连接时
if r is tcp_server_socket:
new_client_socket, client_addr = r.accept()
print("客户端' %s '已经到来" % str(client_addr))
# 将为客户端服务的套接字加入监控列表rlist
rlist.append(new_client_socket)
else:
try:
# 已经连接的客户端发送消息时
recv_data = r.recv(1024)
if recv_data:
# r.getsockname()可以获取套接字绑定的地址
print("客户端' %s '发送过来的请求是: %s" % (str(r.getsockname()), recv_data.decode("utf-8")))
# 服务器回送消息放到主动处理列表wlist
wlist.append(r)
else:
# 如果客户端是调用了close断开了连接,那么需要从监控列表中删除为客户端服务的套接字
rlist.remove(r)
print("已经为 %s 客户端已经服务完毕" % str(r.getsockname()))
# 关闭为客户端服务的套接字
r.close()
except Exception:
traceback.print_exc()
# 遍历需要服务器主动处理的IO列表
for w in ws:
# 回送数据给客户端表示响应客户端的请求
send_data = "----ok----Request accepted"
w.send(send_data.encode("utf-8"))
# 把为客户端服务的套接字从主动处理的列表中删除
wlist.remove(w)
# 遍历异常请求的IO列表
for x in xs:
# 如果监听套接字发生了异常
if x is tcp_server_socket:
# 关闭异常的监听套接字
x.close()
# 退出程序
sys.exit(1) if __name__ == "__main__":
main()

4.TCP客户端-select方法实现IO多路复用

import socket

def main():
# 创建数据流套接字
tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接服务器
server_ip = input("请输入要连接的服务器的ip:")
serve_port = int(input("请输入要连接的服务器的port:"))
server_addr = (server_ip, serve_port)
tcp_client_socket.connect(server_addr)
# 发送数据
send_data = input("请输入要发生的数据:")
tcp_client_socket.send(send_data.encode("utf-8"))
# 接收服务器发送过来的数据
recv_data = tcp_client_socket.recv(1024)
print("接收到的数据为:%s" % recv_data.decode("utf-8"))
# 关闭套接字
tcp_client_socket.close() if __name__ == "__main__":
main()

5.TCP服务器-pool方法实现IO多路复用

import socket
import select
import traceback
import sys def main():
# 创建数据流套接字
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口重用
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 绑定端口,运行局域网内的客户端连接
tcp_server_socket.bind(("0.0.0.0", 7890))
# 让默认的套接字由主动变为被动监听 listen
tcp_server_socket.listen(128)
# 设置套接字超时等待时间为5秒
tcp_server_socket.settimeout(5) # 创建一个IO事件地图
fdmap = {tcp_server_socket.fileno(): tcp_server_socket}
# 创建poll对象
epool_list = select.poll()
# 将监听套接对应的fd注册到poll中进行监听,如果fd已经注册过,则会发生异常
epool_list.register(tcp_server_socket, (select.POLLIN | select.POLLERR)) # 循环目的: 等待新的客户端连接或者已连接的客户端发送过来数据
while True:
print("开始事件监控")
events = epool_list.poll()
for fd, event in events:
if fd == tcp_server_socket.fileno():
new_client_socket, client_addr = tcp_server_socket.accept()
print("客户端' %s '已经到来" % str(client_addr))
epool_list.register(new_client_socket, select.POLLIN)
# 记录这个信息
fdmap[new_client_socket.fileno()] = new_client_socket
elif event & select.POLLIN:
try:
# 已经连接的客户端发送消息时
recv_data = fdmap[fd].recv(1024)
if not recv_data:
# 在poll中注销客户端的信息
epool_list.unregister(fd)
print("已经为客户端已经服务完毕")
# 关闭客户端的文件句柄
fdmap[fd].close()
# 在字典中删除与已关闭客户端相关的信息
del fdmap[fd]
else:
print("客户端发送过来的请求是: %s" % (recv_data.decode("utf-8")))
# 回送数据给客户端表示响应客户端的请求
send_data = "----ok----Request accepted"
fdmap[fd].send(send_data.encode("utf-8"))
except Exception:
traceback.print_exc()
elif event & select.POLLERR:
# 如果监听套接字发生了异常
if fd is tcp_server_socket.fileno():
# 关闭异常的监听套接字
fdmap[fd].close()
# 退出程序
sys.exit(1) if __name__ == "__main__":
main()

6.TCP客户端-pool方法实现IO多路复用

import socket

def main():
# 创建数据流套接字
tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接服务器
server_ip = input("请输入要连接的服务器的ip:")
serve_port = int(input("请输入要连接的服务器的port:"))
server_addr = (server_ip, serve_port)
tcp_client_socket.connect(server_addr)
# 发送数据
send_data = input("请输入要发生的数据:")
tcp_client_socket.send(send_data.encode("utf-8"))
# 接收服务器发送过来的数据
recv_data = tcp_client_socket.recv(1024)
print("接收到的数据为:%s" % recv_data.decode("utf-8"))
# 关闭套接字
tcp_client_socket.close() if __name__ == "__main__":
main()

7.TCP服务器-epool方法实现IO多路复用

import socket
import select
import traceback
import sys def main():
# 创建数据流套接字
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口重用
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# 绑定端口,运行局域网内的客户端连接
tcp_server_socket.bind(("0.0.0.0", 7890))
# 让默认的套接字由主动变为被动监听 listen
tcp_server_socket.listen(128)
# 设置套接字超时等待时间为5秒
tcp_server_socket.settimeout(5) # 创建一个IO事件地图
fdmap = {tcp_server_socket.fileno(): tcp_server_socket}
# 创建poll对象
epool_list = select.poll()
# 将监听套接对应的fd注册到poll中进行监听,如果fd已经注册过,则会发生异常
epool_list.register(tcp_server_socket, (select.EPOLLIN | select.EPOLLERR)) # 循环目的: 等待新的客户端连接或者已连接的客户端发送过来数据
while True:
print("开始事件监控")
events = epool_list.poll()
for fd, event in events:
if fd == tcp_server_socket.fileno():
new_client_socket, client_addr = tcp_server_socket.accept()
print("客户端' %s '已经到来" % str(client_addr))
epool_list.register(new_client_socket, select.EPOLLIN)
# 记录这个信息
fdmap[new_client_socket.fileno()] = new_client_socket
elif event & select.EPOLLIN:
try:
# 已经连接的客户端发送消息时
recv_data = fdmap[fd].recv(1024)
if not recv_data:
# 在poll中注销客户端的信息
epool_list.unregister(fd)
print("已经为客户端已经服务完毕")
# 关闭客户端的文件句柄
fdmap[fd].close()
# 在字典中删除与已关闭客户端相关的信息
del fdmap[fd]
else:
print("客户端发送过来的请求是: %s" % (recv_data.decode("utf-8")))
# 回送数据给客户端表示响应客户端的请求
send_data = "----ok----Request accepted"
fdmap[fd].send(send_data.encode("utf-8"))
except Exception:
traceback.print_exc()
elif event & select.EPOLLERR:
if fd is tcp_server_socket.fileno():
# 关闭异常的监听套接字
fdmap[fd].close()
# 退出程序
sys.exit(1) if __name__ == "__main__":
main()

8.TCP客户端-epool方法实现IO多路复用

import socket

def main():
# 创建数据流套接字
tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接服务器
server_ip = input("请输入要连接的服务器的ip:")
serve_port = int(input("请输入要连接的服务器的port:"))
server_addr = (server_ip, serve_port)
tcp_client_socket.connect(server_addr)
# 发送数据
send_data = input("请输入要发生的数据:")
tcp_client_socket.send(send_data.encode("utf-8"))
# 接收服务器发送过来的数据
recv_data = tcp_client_socket.recv(1024)
print("接收到的数据为:%s" % recv_data.decode("utf-8"))
# 关闭套接字
tcp_client_socket.close() if __name__ == "__main__":
main()

11_IO多路复用的更多相关文章

  1. Python(七)Socket编程、IO多路复用、SocketServer

    本章内容: Socket IO多路复用(select) SocketServer 模块(ThreadingTCPServer源码剖析) Socket socket通常也称作"套接字" ...

  2. Lind.DDD.RedisClient~对StackExchange.Redis调用者的封装及多路复用技术

    回到目录 两雄争霸 使用StackExchange.Redis的原因是因为它开源,免费,而对于商业化的ServiceStack.Redis,它将一步步被前者取代,开源将是一种趋势,商业化也值得被我们尊 ...

  3. IO多路复用概念性

    sellect.poll.epoll三者的区别 先来了解一下什么是进程切换 为了控制进程的执行,内核必须有能力挂起正在CPU上运行的进程,并恢复以前挂起的某个进程的执行,这种行为为进程的切换,任务切换 ...

  4. python学习笔记-(十四)I/O多路复用 阻塞、非阻塞、同步、异步

    1. 概念说明 1.1 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方).操作系统的核心是内核,独立于普通的应用程序,可 ...

  5. IO多路复用之select总结

    1.基本概念 IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程.IO多路复用适用如下场合: (1)当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/ ...

  6. IO多路复用之poll总结

    1.基本知识 poll的机制与select类似,与select在本质上没有多大差别,管理多个描述符也是进行轮询,根据描述符的状态进行处理,但是poll没有最大文件描述符数量的限制.poll和selec ...

  7. IO多路复用之epoll总结

    1.基本知识 epoll是在2.6内核中提出的,是之前的select和poll的增强版本.相对于select和poll来说,epoll更加灵活,没有描述符限制.epoll使用一个文件描述符管理多个描述 ...

  8. Linux I/O多路复用

    Linux中一切皆文件,不论是我们存储在磁盘上的字符文件,可执行文件还是我们的接入电脑的I/O设备等都被VFS抽象成了文件,比如标准输入设备默认是键盘,我们在操作标准输入设备的时候,其实操作的是默认打 ...

  9. python中的IO多路复用

    在python的网络编程里,socetserver是个重要的内置模块,其在内部其实就是利用了I/O多路复用.多线程和多进程技术,实现了并发通信.与多进程和多线程相比,I/O多路复用的系统开销小,系统不 ...

随机推荐

  1. C++/C socket编程

    目录 socket()函数 何为socket Internet套接字 流格式套接字SOCK_STREAM 数据报格式套接字SOCK_DGRAM TCP/IP协议族 创建套接字 加载套接字库 Windo ...

  2. C++实现二叉树的链接存储结构(先根、中根和后根遍历)

    验证二叉树的链接存储结构及其上的基本操作. [实验要求]: 1. 从文件创建一棵二叉树,并对其初始化: 2. 先根.中根.后根遍历二叉树: 3. 在二叉树中搜索给定结点的父结点: 4. 搜索二叉树中符 ...

  3. 2020-05-24:ZK分布式锁有几种实现方式?各自的优缺点是什么?

    福哥答案2020-05-24: Zk分布式锁有两种实现方式一种比较简单,应对并发量不是很大的情况.获得锁:创建一个临时节点,比如/lock,如果成功获得锁,如果失败没获得锁,返回false释放锁:删除 ...

  4. C#LeetCode刷题之#453-最小移动次数使数组元素相等(Minimum Moves to Equal Array Elements)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3877 访问. 给定一个长度为 n 的非空整数数组,找到让数组所有 ...

  5. Web前端性能优化,应该怎么做?

    摘要:本文将分享一些前端性能优化的常用手段,包括减少请求次数.减小资源大小.各种缓存.预处理和长连接机制,以及代码方面的性能优化等方面. base64:尤其是在移动端,小图标可以base64(webp ...

  6. Python+Pytest+Allure+Git+Jenkins接口自动化框架

    Python+Pytest+Allure+Git+Jenkins接口自动化框架 一.接口基础 接口测试是对系统和组件之间的接口进行测试,主要是效验数据的交换,传递和控制管理过程,以及相互逻辑依赖关系. ...

  7. Linux非交互方式设置密码

    echo "123" | passwd -stdin lamp echo testuser:password|chpasswd 参考:Linux通过Shell脚本命令修改密码不需要 ...

  8. SpringBoot--- SpringSecurity进行注销,权限控制

    SpringBoot--- SpringSecurity进行注销,权限控制 环境 IDEA :2020.1 Maven:3.5.6 SpringBoot: 2.0.9 (与此前整合的版本2.3.3 不 ...

  9. SparkStreaming架构

    SparkStreaming是一个对实时数据流进行高通量.容错处理的流式处理系统,可以对多种数据源(如Kdfka.Flume.Twitter.Zero和TCP 套接字)进行类似Map.Reduce和J ...

  10. 一张图带你玩转docker