flask-socket的实践

1.长连接和短连接的由来

1)TCP在真正的读写操作之前,server与client之间必须建立一个连接,

当读写操作完成后,双方不再需要这个连接时它们可以释放这个连接,

连接的建立通过三次握手,释放则需要四次握手,

所以说每个连接的建立都是需要资源消耗和时间消耗的。

2)短连接就是我们平时登陆注册,建立的连接

3)长连接主要适用于通信,比如说qq聊天

2.示例代码

server.py
import socket
import threadingBUF_SIZE = 1024
host = 'localhost'
port = 8083def handle_client(client_socket, address):print("Connected by", address)while True:try:data = client_socket.recv(BUF_SIZE)if not data:print("Connection closed by client", address)breakprint(data.decode())except ConnectionResetError:print("Connection reset by client", address)breakclient_socket.close()server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host, port))
server.listen(5)  # 增加可接收连接数print("Server is listening on port", port)while True:client_socket, address = server.accept()client_handler = threading.Thread(target=handle_client, args=(client_socket, address))client_handler.start()
client.py
import socket
import timehost = 'localhost'
port = 8083client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)  # 开启心跳维护try:client.connect((host, port))print("Connected to server")while True:client.send('hello world\r\n'.encode())print('send data')time.sleep(1)  # 可以设置更长的时间来验证长时间不发送数据的情况
except ConnectionRefusedError:print("Connection failed")
except Exception as e:print("An error occurred:", e)
finally:client.close()

3.flask提供长连接

flask-socket.py
from flask import Flask, render_template
from flask_socketio import SocketIO, sendapp = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)@app.route('/')
def index():return render_template('./index.html')@socketio.on('message')
def handle_message(message):print('Received message: ' + message)send('Message received: ' + message)if __name__ == '__main__':socketio.run(app, debug=True)
html代码
<!DOCTYPE html>
<html><head><title>SocketIO Chat</title><script src="https://cdn.socket.io/4.0.0/socket.io.min.js"></script><script type="text/javascript" charset="utf-8">document.addEventListener('DOMContentLoaded', () => {const socket = io();socket.on('connect', () => {console.log('Connected to server');});socket.on('message', (msg) => {console.log('Message from server: ' + msg);});document.querySelector('#send').addEventListener('click', () => {const message = document.querySelector('#message').value;socket.send(message);});});</script></head><body><input id="message" type="text" placeholder="Enter message"><button id="send">Send</button></body>
</html>

4.flask工厂模式修改为socket

1)目录结构
LongChain/
│
├── app/
│   ├── __init__.py
│   ├── main/
│   │   ├── __init__.py
│   │   ├── routes.py
│   ├── socketio.py
├── templates/
│   └── index.html
├── create_app.py
├── requirements.txt
2)/app/__init__.py
from flask import Flask
from .socketio import socketiodef create_app():app = Flask(__name__, template_folder='../templates')app.config['SECRET_KEY'] = 'secret!'# Initialize SocketIO with the appsocketio.init_app(app)# Import and register blueprintsfrom .main import main as main_blueprintapp.register_blueprint(main_blueprint)print(app.template_folder)  # 打印模板文件夹路径return app3)app/socketio.py
from flask_socketio import SocketIOsocketio = SocketIO()@socketio.on('message')
def handle_message(message):print('Received message: ' + message)socketio.send('Message received: ' + message)
4)app/main/__init__.py
from flask import Blueprintmain = Blueprint('main', __name__)from . import routes
5)app/main/routes.py
from flask import render_template
from . import main@main.route('/')
def index():return render_template('./index.html')
6)templates/index.html
<!DOCTYPE html>
<html><head><title>SocketIO Chat</title><script src="https://cdn.socket.io/4.0.0/socket.io.min.js"></script><script type="text/javascript" charset="utf-8">document.addEventListener('DOMContentLoaded', () => {const socket = io();socket.on('connect', () => {console.log('Connected to server');});socket.on('message', (msg) => {console.log('Message from server: ' + msg);});document.querySelector('#send').addEventListener('click', () => {const message = document.querySelector('#message').value;socket.send(message);});});</script></head><body><input id="message" type="text" placeholder="Enter message"><button id="send">Send</button></body>
</html>
7)create_app.py
from app import create_app
from app.socketio import socketioapp = create_app()if __name__ == "__main__":socketio.run(app, debug=True, host='0.0.0.0')

5.项目代码更改

首先要在app文件夹下建一个extensions.py文件,是为了解决在run.py和init.py里面循环引入socket的问题

1)__init__.py修改
# app/__init__.py
from flask import Flask, render_template, request, g, jsonify, redirect, url_for, session
from app.user.views import user_bp
from app.blog.views import blog_bp
from app.comment.views import comment_bp
from app.drunk1.views import drunk1_bp
from app.onedrunk1.views import onedrunk1_bp
from app.extensions import socketio
import sqlite3
import time
import tracebackdef create_app():app = Flask(__name__, static_url_path='/static')# 加载配置app.config.from_object('config.Config')socketio.init_app(app)# 注册蓝图app.register_blueprint(user_bp, url_prefix='/conversation')app.register_blueprint(blog_bp, url_prefix='/userprofile')app.register_blueprint(comment_bp, url_prefix='/drunk5')app.register_blueprint(drunk1_bp, url_prefix='/drunk1')app.register_blueprint(onedrunk1_bp, url_prefix='/onedrunk1')DATABASE = r'C:\Users\lzt\Desktop\work\flask\app\static\users2.db'# session密钥app.secret_key = 'Cxh12300'current_user = {}def get_db():db = getattr(g, '_database', None)if db is None:db = g._database = sqlite3.connect(DATABASE)return db@app.teardown_appcontextdef close_connection(exception):db = getattr(g, '_database', None)if db is not None:db.close()@app.route('/')def login():return render_template('./login/login.html')@app.route('/regist')def regist():return render_template('./regist/regist.html')@app.route('/registuser', methods=['POST'])def getRigistRequest():try:if request.method == 'POST':username = request.form.get('user')password = request.form.get('password')conn = get_db()cursor = conn.cursor()sql = "INSERT INTO user(user, password) VALUES (?, ?)"cursor.execute(sql, (username, password))conn.commit()return redirect(url_for('login'))else:return render_template('login.html')except Exception as e:traceback.print_exc()return '注册失败'@app.route('/login', methods=['POST'])def getLoginRequest():try:username = request.form.get('user')password = request.form.get('password')conn = get_db()cursor = conn.cursor()sql = "SELECT * FROM user WHERE user=? AND password=?"cursor.execute(sql, (username, password))user = cursor.fetchone()if user:name = user[0]user_id = user[2]current_user['name'] = user[0]current_user['user_id'] = user[2]session['name'] = user[0]session['user_id'] = user[2]current_time = time.time()expiration_time = current_time + 10payload = {'name': name, 'user_id': user_id, 'exp': expiration_time}return render_template('./user/index2qian.html', name=name, user_id=user_id)else:return '用户名或密码不正确'except Exception as e:traceback.print_exc()return '登录失败'return app
2)run.py
from app import create_app, socketioapp = create_app()if __name__ == "__main__":socketio.run(app, debug=True, host='0.0.0.0')
3)app/user/views.py的修改
from flask import Blueprint, render_template,request,jsonify,session
import sqlite3
import traceback
import time
import requests
import json
from flask_socketio import emit
from app.extensions import socketio
user_bp = Blueprint('user', __name__, template_folder='templates')@user_bp.route('/')
def index():return render_template('./user/index2qian.html')
def generate_user_profile(session):# 基本 URLbase_url = "http://192.168.1.140:5000/userprofile/generate_user_profile"# 从 session 中获取 user_id 和 nameprint("session111",session)user_id = session['user_id']name = session['name']print("user_id",user_id)# 构建完整的 URLurl = f"{base_url}?user_id={user_id}&name={name}"try:# 发送 GET 请求response = requests.get(url)# 检查响应状态码if response.status_code == 200:# 成功print("Profile generated successfully")return response.json()else:# 请求失败print(f"Failed to generate profile, status code: {response.status_code}")return Noneexcept Exception as e:print(f"An error occurred: {e}")return None
def get_latest_content_by_user_id(session):# 数据库文件名db_file = r'C:\Users\lzt\Desktop\work\flask\app\static\conversions2.db'# 连接到 SQLite 数据库conn = sqlite3.connect(db_file)cursor = conn.cursor()try:# SQL 查询语句,按 id 降序排列并只获取最新的一条记录query = '''SELECT content FROM profileWHERE user_id = ?ORDER BY id DESCLIMIT 1'''# 执行查询cursor.execute(query, (session['user_id'],))# 获取结果result = cursor.fetchone()if result:content = result[0]  # 获取 content 字段的值return contentelse:return Noneexcept sqlite3.Error as e:print(f"An error occurred: {e}")return Nonefinally:# 关闭数据库连接conn.close()@socketio.on('message')
def handle_message(data):user_input = data['message']conversation_history = data['history']response = ChatBot.call_api(user_input, conversation_history)# print("user_input",user_input)# print("conversation_history",conversation_history)# print("触发emit")# print("response",response)emit('response', {'response': response})class ChatBot:context = Noneconversation_counter = 0@classmethoddef call_api(cls, user_input, conversation_history):# 每十轮对话更新一次 profileprint("cls.conversation_counter:", cls.conversation_counter)if cls.conversation_counter % 10 == 0:print("更新 profile,因为对话计数是 10 的倍数")generate_user_profile(session)profile = get_latest_content_by_user_id(session)if profile:profile_prompt = f"根据你的行为分析,你的兴趣和喜好如下:{profile}\n"print("Profile 更新成功:", profile)else:profile_prompt = ""print("Profile 更新失败或没有新的 profile 数据")else:profile_prompt = ""# 更新对话计数器cls.conversation_counter += 1# API URLurl = 'http://192.168.1.108:11434/api/chat'# 定义基本 promptprompt = ("你只会中文。你只能说中文。""你的性格积极乐观,善良可爱,喜欢和朋友聊天,善解人意。但你不会直说自己的性格。""你喜欢提出问题,并继续聊下去一两句。当你感觉到用户的回答很敷衍的时候,你会找新话题。""你的每句回应要尽可能像真正的朋友。你的回答不可以敷衍。""<人物画像>的意思是对人物行为分析,从而能够区别其喜好等特点.""你对有关用户的<人物画像>的问题都很好奇。如果说了一些性格特征,你会追问一两次,然后开启新的话题。""但你是个情商很高的人,你会说很多种句式的话。你会用中文表达的很完美。""禁止直接提‘人物画像’的字眼。你可以问有关性格爱好的问题,但不能明说<人物画像>一词。""每次说话不多余30个单词。\n")# 将 profile 添加到 prompt 中prompt = profile_prompt + prompt# print("最终 prompt:", prompt)data = {"model": "llama3","messages": conversation_history + [{"role": "user","content": prompt + user_input}],"context": cls.context,"stream": False}headers = {'Content-Type': 'application/json'}data=data_clean(data)# print(type(data))# print('data',data)try:response = requests.post(url, data=json.dumps(data), headers=headers)print("API 请求已发送")# print("json.dumps(data)",json.dumps(data))if response.status_code == 200:response_json = response.json()print("API 响应成功:", response_json)messages = response_json.get('message', {})content = messages.get('content')cls.context = response_json.get('context')return contentelse:print(f'请求失败,状态码: {response.status_code}')print('响应内容:', response.content)return Noneexcept Exception as e:print(f'发生错误: {e}')traceback.print_exc()return None
def data_clean(data):try:messages = data['messages']conversations = []for item in messages:if 'role' in item and 'content' in item:role = "user" if item['role'] == 'user' else "system"content = item['content']conversations.append({'role': role, 'content': content})else:role = item['sender']content = item['message']if role != 'AI':role = 'user'else:role = 'system'conversations.append({'role': role, 'content': content})data['messages']=conversationsreturn dataexcept Exception as e:print(f"数据处理错误: {e}")return None
@user_bp.route('/chat', methods=['POST'])
def chat():data=request.get_data()print("data",data)# user_input=data['message']data_str = data.decode('utf-8')# 将字符串解析为字典data_dict = json.loads(data_str)print("data_dict",data_dict)# 获取 "message" 键对应的值messages = data_dict["message"]userInput=data_dict['userInput']conversations = []for item in messages:role = item["sender"]content = item["message"]if role != "AI":role = "user"else:role = "system"conversations.append({'role': role, 'content': content})response=ChatBot.call_api(userInput,conversations)return jsonify({"response": response})@user_bp.route('/save-message', methods=['POST'])
def save_message():data = request.get_json()print("save_message  data",data)conn = sqlite3.connect('C:\\Users\\lzt\\Desktop\\work\\flask\\app\\static\\conversions2.db')cursor = conn.cursor()for msg in data:message = msg.get('message')timestamp = msg.get('timestamp')sender = msg.get('sender')user_id = msg.get('user_id')  # 获取用户的 user_id# 插入数据到数据库,包括 user_idcursor.execute('''INSERT INTO conversation (timestamp, sender, message, user_id) VALUES (?, ?, ?, ?)''', (timestamp, sender, message, user_id))# 提交更改conn.commit()conn.close()return jsonify({'message': 'Messages saved to database successfully.'})4)前端的修改
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Chat with AI</title><link rel="stylesheet" href="../static/styles.css">
</head>
<body><h1 style="text-align: center;">Chat with AI</h1><div id="chat-container"><div class="message ai-message">AI: Hello there! How can I assist you today?</div></div><div id="userProfile"></div><div id="input-container"><input type="text" id="user-input" placeholder="Your message..." onkeypress="handleKeyPress(event)"><button id="send-button" class="button" onclick="sendMessage()">Send</button><button id="save-button" class="button" onclick="fetchUserProfile()">生成我的用户画像</button><button id="drunk1" class="button" onclick="redirectToDrunk1()">one  drunk</button><button id="onedrunk1" class="button" onclick="redirectToDrunk2()">two drunk</button></div>
</body>
</html>
<script src="https://cdn.socket.io/4.0.0/socket.io.min.js"></script>
<script>function redirectToDrunk1() {var url = "http://192.168.1.140:5000/onedrunk1?user_id=" + encodeURIComponent(userid) + "&name=" + encodeURIComponent(name);window.location.href = url;}function redirectToDrunk2() {window.location.href = "http://192.168.1.140:5000/drunk1";}// 全局变量,记录已经保存到数据库的消息数量var savedMessageCount = 0;var userid = "{{ user_id }}"; // 从服务器端获取的用户IDvar name="{{name}}"console.log("name",name,"userid",userid)function parseMessages() {var chatContainer = document.getElementById('chat-container');var messages = [];chatContainer.querySelectorAll('.message').forEach(message => {messages.push(message.textContent);});console.log("messages",messages)var now = new Date();var year = now.getFullYear();var month = now.getMonth() + 1;var day = now.getDate();var hours = now.getHours();var minutes = now.getMinutes();var formattedTime = year + "-" + month + "-" + day + " " + hours + ":" + minutes;var result = [];if (messages.length >= 20) {messages = messages.slice(-15);}for (var i = 0; i < messages.length; i++) {var message = messages[i];var sender = "";const regex = /([^:]+)/;const messageType = regex.exec(message);if (messageType[0] === "AI") {sender = "AI";} else{sender = userid;}if (sender !== "") {var messageContent = message.substring(message.indexOf(":") + 1);var messageObject = {"timestamp": formattedTime,"sender": sender,"message": messageContent};result.push(messageObject);}}console.log("functionresult",result)return result;
}function isTokenExpired(token) {if (!token) {return true; // 如果没有token,认为已过期}// 从JWT中解析出exp字段,判断是否小于当前时间戳const exp = jwt_decode(token).exp;return exp < Date.now() / 1000;}// 检查JWT是否过期,如果过期则重新登录function checkAndRefreshToken() {const jwt = localStorage.getItem('jwt');if (isTokenExpired(jwt)) {// JWT已过期,重新登录window.location.href = '/login'; // 重定向到登录页面}}function saveToDatabase(message) {// 调用函数检查并刷新JWT// checkAndRefreshToken();// 遍历数据,为每个对象添加"user_id"message.forEach(function(msg) {msg["user_id"] = userid;});// console.log("data", message);var jwt = localStorage.getItem('jwt');// 发送 POST 请求到后端接口fetch('/conversation/save-message', {method: 'POST',headers: {'Content-Type': 'application/json','Authorization': 'Bearer ' + jwt},body: JSON.stringify(message) // 将消息数据转换为 JSON 字符串并作为请求体发送}).then(response => response.json()).then(data => {// 在控制台打印后端返回的响应数据// console.log(data);//  fetchUserProfile();}).catch(error => {// 发生错误时打印错误信息console.error('Error:', error);});}var socket = io.connect('http://' + document.domain + ':' + location.port);socket.on('connect', function() {console.log('Connected to server');
});
socket.on('response', function(data) {var aiMessageDiv = document.createElement('div');aiMessageDiv.classList.add('message', 'ai-message');aiMessageDiv.textContent = 'AI: ' + data.response;console.log("data.response",data.response)document.getElementById('chat-container').appendChild(aiMessageDiv);var chatContainer = document.getElementById('chat-container');var messages = [];chatContainer.querySelectorAll('.message').forEach(message => {messages.push(message.textContent);});var now = new Date();var year = now.getFullYear();var month = now.getMonth() + 1;var day = now.getDate();var hours = now.getHours();var minutes = now.getMinutes();var formattedTime = year + "-" + month + "-" + day + " " + hours + ":" + minutes;var result = [];for (var i = savedMessageCount; i < messages.length; i++) {var message = messages[i];var sender = "";const regex = /([^:]+)/; // 匹配 ":" 之前的任意字符(不包括 ":"),并且只提取匹配到的内容const messageType = regex.exec(message);console.log("messageType[0] ", messageType[0] )if (messageType[0] === "AI") {sender = "AI";} else {sender = userid;}// console.log("sender",sender)if (sender !== "") {var messageContent = message.substring(message.indexOf(":") + 1);// console.log("messageContent",messageContent)var messageObject = {"timestamp": formattedTime,"sender": sender,"message": messageContent};// console.log("messageObject",messageObject)result.push(messageObject);}}savedMessageCount = messages.length;console.log("result", result);saveToDatabase(result);});async function sendMessage() {var userInput = document.getElementById('user-input').value.trim();if (userInput === '') {return;}var chatContainer = document.getElementById('chat-container');var userMessageDiv = document.createElement('div');userMessageDiv.classList.add('message', 'user-message');userMessageDiv.textContent = name +':'+ userInput;chatContainer.appendChild(userMessageDiv);newValue=parseMessages();socket.emit('message', {message: userInput,history: newValue});document.getElementById('user-input').value = '';}function handleKeyPress(event) {if (event.key === 'Enter' && !event.shiftKey) { // 检查是否按下了 Enter 键且未按下 Shift 键event.preventDefault(); // 阻止默认的 Enter 键行为(即提交表单)sendMessage(); // 调用 sendMessage 函数发送消息} else if (event.key === 'Enter' && event.shiftKey) { // 如果同时按下了 Shift 键和 Enter 键var input = document.getElementById('user-input');var start = input.selectionStart;var end = input.selectionEnd;var value = input.value;input.value = value.substring(0, start) + '\n' + value.substring(end);input.selectionStart = input.selectionEnd = start + 1; // 将光标移动到换行符后}}function saveConversation() {var chatContainer = document.getElementById('chat-container');var messages = [];// 遍历聊天容器中的所有消息,并将其保存到数组中chatContainer.querySelectorAll('.message').forEach(message => {messages.push(message.textContent);});var now = new Date();var year = now.getFullYear(); // 获取年份var month = now.getMonth() + 1; // 获取月份(注意要加1,因为月份是从0开始的)var day = now.getDate(); // 获取日期var hours = now.getHours(); // 获取小时var minutes = now.getMinutes(); // 获取分钟var formattedTime = year + "-" + month + "-" + day + " " + hours + ":" + minutes;var result = [];for (var i = 0; i < messages.length; i++) {var message = messages[i];var sender = "";var messageType = message.substring(0, 4);// 根据消息类型确定发送者if (messageType === "AI: ") {sender = "AI";} else if (messageType === "User") {sender = userid;}// 构造消息对象并添加到结果数组中if (sender !== "") {var messageContent = message.substring(message.indexOf(":") + 2); // 获取冒号后面的消息内容// console.log(messageContent)var messageObject = {"timestamp": formattedTime,"sender": sender,"message": messageContent};result.push(messageObject);}}}function fetchUserProfile() {
fetch( 'http://192.168.1.140:5000/userprofile/generate_user_profile?user_id=' + userid + '&name=' + name, {method: 'GET',headers: {'Content-Type': 'application/json',},
})
.then(response => {if (!response.ok) {throw new Error('Network response was not ok');}return response.text(); // 直接获取文本内容
})
.then(data => {console.log("response.data", data);// 这里可以对返回的文本内容进行处理,例如将其显示在页面上const userProfileDiv = document.getElementById('userProfile');userProfileDiv.innerText = data;
})
.catch(error => {console.error('Error:', error);
});
}</script>

主要就是前端点击发送按钮触发

            socket.emit('message', {

                message: userInput,

                history: newValue

            });

然后后端接受前端传的消息并且调用对应的方法传参,再将结果传给前端

@socketio.on('message')

def handle_message(data):

    user_input = data['message']

    conversation_history = data['history']

    response = ChatBot.call_api(user_input, conversation_history)

    # print("user_input",user_input)

    # print("conversation_history",conversation_history)

    # print("触发emit")

    # print("response",response)

    emit('response', {'response': response})

前端收到返回的信息socket.on('response', function(data) {)
进行下一步的处理

  • 后端:

    • 监听客户端连接、断开连接和消息事件。
    • 接收到消息后,将其广播给所有连接的客户端。
  • 前端:

    • 监听服务器广播的消息事件,并在页面上显示消息。
    • 监听表单提交事件,发送用户输入的消息到服务器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/36519.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用Roofline模型去分析pytorch和Triton算子

用Roofline模型去分析pytorch和Triton算子 1.参考链接2.测试环境3.安装相关依赖4.锁频5.获取理论算力6.创建测试脚本7.运行测试程序生成Roofline图8.NVIDIA Nsight Compute生成Roofline9.效果图A.nn.LinearB.Triton实现 本文演示了如何用Roofline模型去分析pytorch和Triton算子…

【银河麒麟】unzip程序卡住,处理机制详解,附代码

1.服务器环境以及配置 【机型】 处理器&#xff1a; HUAWEI,Kunpeng 920 内存&#xff1a; 400G 【内核版本】 4.19.90-23.18.v2101.ky10.aarch64 【OS镜像版本】 银河麒麟高级服务器操作系统V10-SP1-0711-arm 【第三方软件】 docker 2.问题现象描述 一台k8s服务器…

水上实用救生工具_救生拉杆_鼎跃安全

每年&#xff0c;由于水上事故而失去生命的人数不胜数&#xff0c;水上安全问题也成为公众关注的焦点。如何在关键时刻实施有效的救援&#xff0c;成为保障生命的重要课题。作为水上救援的重要工具&#xff0c;救生拉杆在紧急情况下发挥了无可替代的作用。 救生拉杆&#xff0c…

springboot 缓存框架Cache整合redis组成二级缓存

springboot 缓存框架Cache整合redis组成二级缓存 项目性能优化的解决方案除开硬件外的方案无非就是优化sql&#xff0c;减少sql 的执行时间&#xff0c;合理运用缓存让同样的请求和数据库之间的连接尽量减少&#xff0c;内存的处理速度肯定比直接查询数据库来的要快一些。今天就…

CDP问卷的常见问题

CDP问卷的常见问题可以归纳如下&#xff1a; 哪些企业会收到CDP邀请&#xff1f; 企业会收到来自投资和/或采购机构的邀请&#xff0c;以填写CDP问卷并披露相应的环境管理信息。 未收到邀请的企业可否填报&#xff1f; 未收到邀请的企业可以选择自行填报。他们需发送申请自愿…

多线程(基础)

前言&#x1f440;~ 上一章我们介绍了什么是进程&#xff0c;对于进程就了解那么多即可&#xff0c;我们作为java程序员更关注线程&#xff0c;线程内容比较多&#xff0c;所以我们要分好几部分才能讲完 目录 进程的缺点 多线程&#xff08;重要&#xff09; 进程和线程的区…

鸿蒙开发Ability Kit(程序框架服务):【FA模型切换Stage模型指导】 module的切换

module的切换 从FA模型切换到Stage模型时&#xff0c;开发者需要将config.json文件module标签下的配置迁移到module.json5配置文件module标签下&#xff0c;具体差异见下列表格。 表1 FA模型module标签与Stage模型module标签差异对比 FA标签标签说明对应的Stage标签差异说明…

LeetCode刷题之HOT100之课程表

吃完普通的食堂饭菜&#xff0c;回到实验室&#xff0c;继续做一道题&#xff01; 1、题目描述 2、逻辑分析 这道题涉及到图相关知识&#xff0c;应用到了拓扑排序。 题意解释 一共有 n 门课要上&#xff0c;编号为 0 ~ n-1。先决条件 [1, 0]&#xff0c;意思是必须先上课 0…

触动心弦的成语之旅:《米小圈动画成语》带你走进中华智慧

成语&#xff0c;这些古老而典雅的语言精华&#xff0c;如同中华文化的晶莹明珠&#xff0c;闪耀着历史的光辉和智慧的火花。从古至今&#xff0c;它们在中国人的日常交流中扮演着重要角色&#xff0c;不仅传递着深刻的哲理和文化内涵&#xff0c;更是凝聚了世代智者的思想和智…

【Linux】线程id与互斥(线程三)

上一期我们进行了线程控制的了解与相关操作&#xff0c;但是扔就有一些问题没有解决 本章第一阶段就是解决tid的问题&#xff0c;第二阶段是进行模拟一个简易线程库&#xff08;为了加深对于C库封装linux原生线程的理解&#xff09;&#xff0c;第三阶段就是互斥。 目录 线程id…

链在一起怎么联机 链在一起远程同玩联机教程

steam中最近特别热门的多人跑酷冒险的游戏&#xff1a;《链在一起》&#xff0c;英文名称叫做Chained Together&#xff0c;在游戏中我们需要开始自己的旅程&#xff0c;在地狱的深处&#xff0c;与我们的同伴被链在一起。我们的任务是通过尽可能高的攀登逃离地狱。每一次跳跃都…

Python第三方库GDAL 安装

安装GDAL的方式多种&#xff0c;包括pip、Anaconda、OSGeo4W等。笔者在安装过程中&#xff0c;唯独使用pip安装遇到问题。最终通过轮子文件&#xff08;.whl&#xff09;成功安装。 本文主要介绍如何下载和安装较新版本的GDAL轮子文件。 一、GDAL轮子文件下载 打开Github网站…

Python学习打卡:day16

day16 笔记来源于&#xff1a;黑马程序员python教程&#xff0c;8天python从入门到精通&#xff0c;学python看这套就够了 目录 day16116、SQL 基础和 DDLSQL的概述SQL语言的分类SQL的语法特征DDL — 库管理DDL — 表管理 117、SQL — DMLDML概述数据插入 INSERT数据删除 DEL…

深入理解 Dubbo:分布式服务框架的核心原理与实践

目录 Dubbo 概述Dubbo 的架构Dubbo 的关键组件 服务提供者&#xff08;Provider&#xff09;服务消费者&#xff08;Consumer&#xff09;注册中心&#xff08;Registry&#xff09;监控中心&#xff08;Monitor&#xff09;调用链追踪&#xff08;Trace&#xff09; Dubbo 的…

专题页面设计指南:从构思到实现

如何设计专题页&#xff1f;你有什么想法&#xff1f;专题页的设计主要以发扬产品优势为核心。一个好的专题页可以从不同的角度向用户介绍产品&#xff0c;扩大产品的相关优势&#xff0c;表达产品的优势&#xff0c;让用户在短时间内了解产品。因此&#xff0c;在设计详细信息…

纯血鸿蒙Beta版本发布,中国华为,站起来了!

2024年6月21日至23日&#xff0c;华为开发者大会2024&#xff08;HDC 2024&#xff09;于东莞盛大举行。 此次大会不仅在会场设置了包括鸿蒙原生应用、统一生态统一互联等在内的11个展区&#xff0c;以供展示HarmonyOS NEXT的强大实力&#xff0c;还对外宣布了HarmonyOS的最新进…

240627_关于CNN中图像维度变化问题

240627_关于CNN中图像维度变化问题 在学习一些经典模型时&#xff0c;其中得维度变化关系总搞不太明白&#xff0c;集中学习了以下&#xff0c;在此作以梳理总结&#xff1a; 一般来说涉及到的维度变换都是四个维度&#xff0c;当batch size4&#xff0c;图像尺寸为640*640&a…

kylin v10 离线安装chrome centos离线安装chrome linux离线安装谷歌浏览器

1. 先用自己联网的计算机&#xff0c;下载离线安装包&#xff0c;浏览器输入链接下载安装包&#xff1a; https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm 1.2. 信创环境不用执行下面&#xff0c;因为没网 1.3. 若为阿里云服务器&#xff0c;或服…

AR导航技术加持,图书馆阅读体验智慧升级

在信息爆炸的今天&#xff0c;图书馆作为知识的宝库&#xff0c;其藏书量和种类日益增多。然而&#xff0c;传统的图书馆导航方式已逐渐无法满足用户对快速、准确定位图书的需求。本文将探讨图书馆AR地图导航的实现原理、技术优势、功能特点以及市场前景&#xff0c;揭示为何AR…

VS studio2019配置远程连接Ubuntu

VS studio2019配置远程连接Ubuntu 1、网络配置 &#xff08;1&#xff09;获取主机IP &#xff08;2&#xff09;获取Ubuntu的IP &#xff08;3&#xff09;在 windows 的控制台中 ping 虚拟机的 ipv4 地址&#xff0c;在 Ubuntu 中 ping 主机的 ipv4 地址。 ubuntu: ping…