Flask:线程安全 + 偏函数 + flask上下文 + 群聊单聊(geventwebsocket)
线程安全
示例一:
线程不安全的多线程小程序,多个线程之间会数据会发生混乱,不准确
import time import threading # from threading import local class Foo(object): # 继承object 是不安全的 pass foo=Foo() def add(i): foo.name=i time.sleep(1) print(foo.name,i,threading.current_thread().ident) for i in range(5): th = threading.Thread(target=add,args=(i,)) th.start() '''
结果: 4 2 8136 4 1 12632 4 0 2068 4 4 5488 4 3 13900 分析: 因为停止一秒钟,每个进程再执行add函数,但是foo.name中地址都是一样的, 通过循环,foo.name=i 已经在1秒内执行到最后i变为4了 因此打印的都是4,与i值不对应,造成了混乱,这样的线程是不安全的 '''
示例二:
解决上线线程不安全的问题,用了local
import time import threading from threading import local class Foo(local): # 这里继承local即可,不需要做其他的改动 pass foo=Foo() def add(i): foo.name=i time.sleep(1) print(foo.name,i,threading.current_thread().ident) for i in range(5): th = threading.Thread(target=add,args=(i,)) th.start() ''' 为了解决线程安全问题,创建的类中继承local就可以了 将上面的代码做如上的更改: 结果会一一对应: 0 0 4820 1 1 3412 3 3 11448 2 2 8372 4 4 15400 '''
偏函数
是将函数先partial到偏函数先不执行,等执行的时候再调用,在看flask的上下文源码的时候会看到
from functools import partial def func(a,*args): print(a,args) return a par_ab = partial(func,1) # partial(函数名,参数a),得到的par_ab就是偏函数,func此时不会执行,1 作为参数传进 func print(par_ab) # 打印偏函数,得到的是偏函数的地址 print(par_ab(2)) # 2 传入的参数对应的是args;此时 func函数会执行,打印参数a args; 本身该句话要打印偏函数的返回值 a=1 # functools.partial(<function func at 0x0000025EDC5D9F28>, 1) # 1 (2,) # 1
flask上下文
上下文主要是看源码,分析app.run()内部是如何执行的
上文:主要是如何获取到request的
下文:主要是request.method 属性是如何调用的
这里需要继续看源码:
1、werkzeug中的run_simple()
app.run()简单原理解析 from flask import Flask app = Flask(__name__) @app.route("/") def index(): return 'ok' if __name__ == '__main__': app.run(debug=True) ''' flask的运行机制,app.run() 实际上就是封装了,run_simple ''' # 下面是一个简单的 run_simple 启动flask # 也是app.run()的原理 from werkzeug.serving import run_simple from werkzeug.wrappers import Response,Request @Request.application def app(request): print(request.path) return Response("200 OK!") run_simple("0.0.0.0",5000,app) # 当有请求来的时候,会调用app,app():对象加括号会调用 __call__()方法
2、flask上下文
单聊群聊(geventwebsocket)
后端 01.py
import json from flask import Flask, render_template, request from gevent.pywsgi import WSGIServer from geventwebsocket.handler import WebSocketHandler from geventwebsocket.websocket import WebSocket app = Flask(__name__) @app.route("/") def index(): return render_template('talk.html') user_socket_dict = {} @app.route('/ws/<username>') def ws(username): user_socket = request.environ.get('wsgi.websocket') # 每次有登录访问,就会替换掉上次的内容websocket if user_socket: user_socket_dict[username] = user_socket # 有人访问就将该用户的websocket添加到字典中,存储所有登录人的socket print("user_socket_dict",user_socket_dict) while 1: # ----------------- 单聊 ----------------------------- msg = user_socket.receive() # 在这里会夯住,等待接收 前端 send()的信息 print(msg) msg_dict = json.loads(msg) msg_dict['from_user'] = username to_user = msg_dict.get('to_user') # 获取到收件人的username u_socket = user_socket_dict.get(to_user) # 获取收件人的websocket信息
u_socket.send(json.dumps(msg_dict)) # 给收件人发送消息 #--------------------- 群聊 ----------------------------- # msg = user_socket.receive() # for u_socket in user_socket_dict.values(): # 群聊,去values即可,给聊表中的每一个websocket都发送收到的消息 # u_socket.send(msg) if __name__ == '__main__': # app.run(debug=True) # 利用WSGIServer来开启服务,代替之前的app.run http_serv = WSGIServer(('0.0.0.0', 5001), app, handler_class=WebSocketHandler) http_serv.serve_forever() ''' user_socket_dict = {'alex': <geventwebsocket.websocket.WebSocket object at 0x0000020C636D62B8>, 'chen': <geventwebsocket.websocket.WebSocket object at 0x0000020C636D6250>} '''
前端 talk.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>欢迎来到聊天界面</h1> <!-- 如果这里使用form标签包起来的话,里面的button一定要指明是type='button' --> <input type="text" id="username"> <button onclick="login()">登录聊天室</button> 给<input type="text" id="to_user">发送:<input type="text" id="msg"> <button onclick="send_msg()">发送</button> <div id="chat_list" style="background: lightgoldenrodyellow;width: 500px;height: 500px;"></div> </body> <script type="application/javascript"> var ws = null; function login() { var username = document.getElementById("username").value; <!-- 生成ws websocket 访问后端, onmessage 是后端send返回的数据 --> ws = new WebSocket('ws://192.168.100.1:5001/ws/' + username); ws.onmessage = function (data) { console.log(data.data); var recv_msg = JSON.parse(data.data); var ptag = document.createElement('P'); ptag.innerText = recv_msg.from_user + ':' + recv_msg.msg; document.getElementById('chat_list').appendChild(ptag); } } function send_msg() { var to_user = document.getElementById('to_user').value; var msg = document.getElementById('msg').value; var send_str = { "to_user": to_user, "msg": msg }; <!-- 这里是给后端发送数据 --> ws.send(JSON.stringify(send_str)); } </script> </html>

浙公网安备 33010602011771号