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. “随手记”APP与已经发布的记账软件“鲨鱼记账”的差距

    我们使用并观察了“鲨鱼记账”APP,发现,我们的软件真的还有很多不足的地方.就功能这方面来说:“鲨鱼记账”APP有更多的收入.支出分类:就界面来说:“鲨鱼记账”APP有比我们优美太多的页面和背景.但是 ...

  2. Prometheus监控神器-Rules篇

    本章主要对如何使用Prometheus与Alertmanager组件集成配置,以及对警报规则 Rules 的俩种类型及其模板内容进行讲解. 与Alertmanager集成 Prometheus把产生的 ...

  3. C#LeetCode刷题之#641-设计循环双端队列(Design Circular Deque)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/4132 访问. 设计实现双端队列. 你的实现需要支持以下操作: M ...

  4. 个性探测综述阅读笔记——Recent trends in deep learning based personality detection

    目录 abstract 1. introduction 1.1 个性衡量方法 1.2 应用前景 1.3 伦理道德 2. Related works 3. Baseline methods 3.1 文本 ...

  5. Android开发学习进程0.18 SharePreference的使用 AIDL

    SharePreference SharePreference是一种持久化存储手段,使用场景很多,如第一次打开时加载的用户协议等.适合小数据单进程的应用.将数据以键值对的形式存储在XML中. 使用方式 ...

  6. troubleshoot之:使用JFR分析性能问题

    目录 简介 GC性能事件 同步性能 IO性能 代码执行的性能 其他有用的event 简介 java程序的性能问题分析是一个很困难的问题.尤其是对于一个非常复杂的程序来说,分析起来更是头疼. 还好JVM ...

  7. Kubernetes实战指南(三十三):都0202了,你还在手写k8s的yaml文件?

    目录 1. k8s的yaml文件到底有多复杂 2. 基于图形化的方式自动生成yaml 2.1 k8s图形化管理工具Ratel安装 2.2 使用Ratel创建生成yaml文件 2.2.1 基本配置 2. ...

  8. Go 切片的一种有趣内存泄漏方式

    今天我在看 Prashant Varanasi 的 Go 发布会演讲:使用火焰图进行生产分析(Analyzing production using Flamegraphs),在演讲开始的第 28 分钟 ...

  9. 微信公众号请求code时报redirect_uri 参数错误

    (1) 检查微信公众号中"接口权限"--"网页授权获取用户基本信息"中的网页授权域名.域名不带http(s) (2)如果在拼接跳转到微信授权接口的URL时,使用 ...

  10. springMVC入门(四)------参数绑定与返回值类型

    简介 从之前的介绍,已经可以使用springMVC完成完整的请求.返回数据的功能. 待解决的问题:如何将数据传入springMVC的控制器进行后续的处理,完成在原生servlet/jsp开发中Http ...