SocketIO 连续 emit() 变慢
SocketIO slowing on consecutive emit()
我正在尝试制作一个简单的脚本来将事件从 python 应用程序推送到客户端。我制作了一个 Console
React 组件,它使用 SocketIO 接收事件,我正在使用 Flask SocketIO 推送消息。
这是我的 app.py
:
from flask import Flask, request
from flask_socketio import SocketIO, send
app = Flask(__name__)
socketio = SocketIO(app, cors_allowed_origins='*')
@app.route('/send/<int:n>')
def send_n(n):
for i in range(n):
socketio.emit('console', str(i+1))
socketio.sleep(0.1)
return 'OK'
if __name__ == '__main__':
socketio.run(app)
函数send_n(n)
只是将n
个事件推送到客户端,间隔为0.25s。
这是 简化的 Console
组件(它重现了不良行为):
import { useState, useEffect } from 'react'
import '../styles/console.css'
import { Socket } from 'socket.io-client'
interface ConsoleProps {
socket: Socket
}
export default function Console(props: ConsoleProps) {
const [messages, setMessages] = useState<string[]>([])
useEffect(() => {
props.socket.on('console', msg => {
setMessages([...messages, `${new Date().toLocaleTimeString()} ${msg}`])
})
})
return (
<div className='console' style={{ height: '200px' }}>
<ul>
{messages.map((msg, i) => <li key={i}>{msg}</li>)}
</ul>
</div>
)
}
它通过 props 接收已经连接的套接字。
组件呈现良好直到它有 ~10 个元素,但随后它变慢并在第 13 行冻结,我什至无法关闭选项卡而不必先终止进程。
Flask 的调试器为呈现的每一行注册消息,但未呈现的行(我尝试使用 25 作为 n
的值)似乎从未发送过。
所以我有两个问题:
- 为什么 flask 没有发送每条消息?某种糟糕的排队?
- 为什么当后端套接字冻结时反应会冻结?
此外,如果我将 msg
设置为时间戳,第一条消息会快速呈现,但后端时间戳和 React 时间戳之间的差异会随着消息数量的增加而迅速增长。
我根据@Miguel 的评论解决了它。
长话短说,useEffect()
函数在每次渲染时执行,每次执行时都会添加一个新的处理程序 而不会删除之前的处理程序 ,所以在少数会使事情呈指数级失控。所以我只是添加了一行以在它完成时删除处理程序。
useEffect(():any => {
props.socket.on('console', msg => {
setMessages([...messages, `${new Date().toLocaleTimeString()} ${msg}`])
})
return () => props.socket.off('console')
})
现在渲染没有问题了。
我正在尝试制作一个简单的脚本来将事件从 python 应用程序推送到客户端。我制作了一个 Console
React 组件,它使用 SocketIO 接收事件,我正在使用 Flask SocketIO 推送消息。
这是我的 app.py
:
from flask import Flask, request
from flask_socketio import SocketIO, send
app = Flask(__name__)
socketio = SocketIO(app, cors_allowed_origins='*')
@app.route('/send/<int:n>')
def send_n(n):
for i in range(n):
socketio.emit('console', str(i+1))
socketio.sleep(0.1)
return 'OK'
if __name__ == '__main__':
socketio.run(app)
函数send_n(n)
只是将n
个事件推送到客户端,间隔为0.25s。
这是 简化的 Console
组件(它重现了不良行为):
import { useState, useEffect } from 'react'
import '../styles/console.css'
import { Socket } from 'socket.io-client'
interface ConsoleProps {
socket: Socket
}
export default function Console(props: ConsoleProps) {
const [messages, setMessages] = useState<string[]>([])
useEffect(() => {
props.socket.on('console', msg => {
setMessages([...messages, `${new Date().toLocaleTimeString()} ${msg}`])
})
})
return (
<div className='console' style={{ height: '200px' }}>
<ul>
{messages.map((msg, i) => <li key={i}>{msg}</li>)}
</ul>
</div>
)
}
它通过 props 接收已经连接的套接字。
组件呈现良好直到它有 ~10 个元素,但随后它变慢并在第 13 行冻结,我什至无法关闭选项卡而不必先终止进程。
Flask 的调试器为呈现的每一行注册消息,但未呈现的行(我尝试使用 25 作为 n
的值)似乎从未发送过。
所以我有两个问题:
- 为什么 flask 没有发送每条消息?某种糟糕的排队?
- 为什么当后端套接字冻结时反应会冻结?
此外,如果我将 msg
设置为时间戳,第一条消息会快速呈现,但后端时间戳和 React 时间戳之间的差异会随着消息数量的增加而迅速增长。
我根据@Miguel 的评论解决了它。
长话短说,useEffect()
函数在每次渲染时执行,每次执行时都会添加一个新的处理程序 而不会删除之前的处理程序 ,所以在少数会使事情呈指数级失控。所以我只是添加了一行以在它完成时删除处理程序。
useEffect(():any => {
props.socket.on('console', msg => {
setMessages([...messages, `${new Date().toLocaleTimeString()} ${msg}`])
})
return () => props.socket.off('console')
})
现在渲染没有问题了。