Qwen2.5-7B-Instruct vLLM 部署调用

Qwen2.5-7B-Instruct vLLM 部署调用

vLLM 简介

vLLM 框架是一个高效的大语言模型推理和部署服务系统,具备以下特性:

  • 高效的内存管理:通过 PagedAttention 算法,vLLM 实现了对 KV 缓存的高效管理,减少了内存浪费,优化了模型的运行效率。
  • 高吞吐量vLLM 支持异步处理和连续批处理请求,显著提高了模型推理的吞吐量,加速了文本生成和处理速度。
  • 易用性vLLMHuggingFace 模型无缝集成,支持多种流行的大型语言模型,简化了模型部署和推理的过程。兼容 OpenAIAPI 服务器。
  • 分布式推理:框架支持在多 GPU 环境中进行分布式推理,通过模型并行策略和高效的数据通信,提升了处理大型模型的能力。
  • 开源共享vLLM 由于其开源的属性,拥有活跃的社区支持,这也便于开发者贡献和改进,共同推动技术发展。

环境准备

本文基础环境如下:

----------------
ubuntu 22.04
python 3.12
cuda 12.1
pytorch 2.4.0
----------------

本文默认学习者已配置好以上 Pytorch (cuda) 环境,如未配置请先自行安装。

首先 pip 换源加速下载并安装依赖包

python -m pip install --upgrade pip
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simplepip install modelscope==1.20.0
pip install transformers==4.46.2
pip install torch==2.4.0 torchvision==0.19.0 torchaudio==2.4.0 --index-url https://download.pytorch.org/whl/cu121
pip install vllm==0.6.3.post1
pip install accelerate==0.26.0

考虑到部分同学配置环境可能会遇到一些问题,我们在AutoDL平台准备了Qwen2.5的环境镜像,点击下方链接并直接创建Autodl示例即可。
https://www.codewithgpu.com/i/datawhalechina/self-llm/qwen2.5-coder

模型下载

使用 modelscope 中的 snapshot_download 函数下载模型,第一个参数为模型名称,参数 cache_dir 为模型的下载路径。

在新建 model_download.py 文件并在其中输入以下内容,粘贴代码后记得保存文件,如下图所示。并运行 python model_download.py 执行下载,模型大小为 16 GB,下载模型大概需要 12 分钟。

from modelscope import snapshot_downloadsnapshot_download('Qwen/Qwen2.5-Coder-7B-Instruct', local_dir='/root/autodl-tmp/Qwen2.5-Coder-7B-Instruct')

注意:记得修改 local_dir 为你的模型下载路径哦~
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

代码准备

Python脚本

/root/autodl-tmp 路径下新建 vllm_model.py 文件并在其中输入以下内容,粘贴代码后请及时保存文件。下面的代码有很详细的注释,如有不理解的地方,欢迎大家提 issue

首先从 vLLM 库中导入 LLMSamplingParams 类。LLM 类是使用 vLLM 引擎运行离线推理的主要类。SamplingParams 类指定采样过程的参数,用于控制和调整生成文本的随机性和多样性。

vLLM 提供了非常方便的封装,我们直接传入模型名称或模型路径即可,不必手动初始化模型和分词器。

我们可以通过这个代码示例熟悉下 vLLM 引擎的使用方式。被注释的部分内容可以丰富模型的能力,但不是必要的,大家可以按需选择,自己多多动手尝试 ~

# vllm_model.py
from vllm import LLM, SamplingParams
from transformers import AutoTokenizer
import os
import jsondef prepare_model(model_path,  max_tokens=512, temperature=0.8, top_p=0.95, max_model_len=2048):# 初始化 vLLM 推理引擎llm = LLM(model=model_path, tokenizer=model_path, max_model_len=max_model_len,trust_remote_code=True)return llmdef get_completion(prompts, llm, max_tokens=512, temperature=0.8, top_p=0.95, max_model_len=2048):stop_token_ids = [151329, 151336, 151338]# 创建采样参数。temperature 控制生成文本的多样性,top_p 控制核心采样的概率sampling_params = SamplingParams(temperature=temperature, top_p=top_p, max_tokens=max_tokens, stop_token_ids=stop_token_ids)# 初始化 vLLM 推理引擎outputs = llm.generate(prompts, sampling_params)return outputs# 初始化 vLLM 推理引擎
model_path = './Qwen2.5-Coder-7B-Instruct'
tokenizer = AutoTokenizer.from_pretrained(model_path)
llm = prepare_model(model_path)prompt = "帮我使用torch写一个用于手写数字识别的模型"
messages = [{"role": "system", "content": "你是一个有用的助手。"},{"role": "user", "content": prompt}
]# 应用template中的chat模板
text = tokenizer.apply_chat_template(messages,tokenize=False,add_generation_prompt=True
)outputs = get_completion(text, llm, max_tokens=1024, temperature=1, top_p=1, max_model_len=2048)
print(outputs[0].outputs[0].text)

运行代码

cd /root/autodl-tmp && python vllm_model.py

结果如下:

Prompt: '帮我使用torch写一个用于手写数字识别的模型', Generated text: ' 当然可以!下面是一个使用PyTorch编写的简单卷积神经网络(CNN),用于手写数字识别。这个模型使用的是MNIST数据集。\n\n首先,确保你已经安装了PyTorch。如果没有安装,可以使用以下命令进行安装:\n\n```bash\npip install torch torchvision\n```\n\n接下来是代码:\n\n```python\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torchvision\nimport torchvision.transforms as transforms\n\n# 定义超参数\nbatch_size = 64\nlearning_rate = 0.001\nnum_epochs = 10\n\n# 转换数据\ntransform = transforms.Compose([\n    transforms.ToTensor(),\n])\n\n# 加载MNIST数据集\ntrain_dataset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transform)\ntest_dataset = torchvision.datasets.MNIST(root='./data', train=False, download=True, transform=transform)\n\n# 创建数据加载器\ntrain_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)\ntest_loader = torch.utils.data.DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=False)\n\n# 定义卷积神经网络模型\nclass CNN(nn.Module):\n    def __init__(self):\n        super(CNN, self).__init__()\n        self.conv1 = nn.Conv2d(in_channels=1, out_channels=32, kernel_size=3, stride=1, padding=1)\n        self.conv2 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, stride=1, padding=1)\n        self.pool = nn.MaxPool2d(kernel_size=2, stride=2, padding=0)\n        self.fc1 = nn.Linear(in_features=64 * 7 * 7, out_features=128)\n        self.fc2 = nn.Linear(in_features=128, out_features=10)\n\n    def forward(self, x):\n        x = self.pool(nn.functional.relu(self.conv1(x)))\n        x = self.pool(nn.functional.relu(self.conv2(x)))\n        x = x.view(-1, 64 * 7 * 7)\n        x = nn.functional.relu(self.fc1(x))\n        x = self.fc2(x)\n        return x\n\n# 实例化模型、损失函数和优化器\nmodel = CNN()\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=learning_rate)\n\n# 训练模型\nfor epoch in range(num_epochs):\n    model.train()\n    running_loss = 0.0\n    for i, (images, labels) in enumerate(train_loader):\n        optimizer.zero_grad()\n        outputs = model(images)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n        \n        running_loss += loss.item()\n        if (i+1) % 100 == 0:\n            print(f'Epoch [{epoch+1}/{num_epochs}], Step [{i+1}/{len(train_loader)}], Loss: {running_loss/100:.4f}')\n            running_loss = 0.0\n\nprint('Finished Training')\n\n# 测试模型\nmodel.eval()\nwith torch.no_grad():\n    correct = 0\n    total = 0\n    for images, labels in test_loader:\n        outputs = model(images)\n        _, predicted = torch.max(outputs.data, 1)\n        total += labels.size(0)\n        correct += (predicted == labels).sum().item()\n\n    print(f'Accuracy of the model on the 10000 test images: {100 * correct / total:.2f}%')\n```\n\n这个代码包括以下部分:\n\n1. 数据加载和预处理。\n2. 定义了一个简单的卷积神经网络模型。\n3. 训练模型。\n4. 测试模型。\n\n运行这个代码后,你将看到模型的训练过程和最终的测试准确率。希望这对你有帮助!'Prompt: '帮我写一个用于登陆的Servlet', Generated text: ' 好的,我来为您提供一个简单的用于登录的Servlet示例。这个示例将使用Java的Servlet API,并假设您正在使用Java EE或Servlet 3.1以上版本的容器。以下是一个基本的实现:\n\n```java\nimport java.io.IOException;\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\nimport javax.servlet.http.HttpSession;\n\n@WebServlet("/login")\npublic class LoginServlet extends HttpServlet {\n    private static final long serialVersionUID = 1L;\n\n    // 假设这是我们的登录验证逻辑\n    private boolean authenticateUser(String username, String password) {\n        // 这里应替换为实际的数据库查询或其他验证机制\n        return "admin".equals(username) && "password".equals(password);\n    }\n\n    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\n        // 获取表单提交的用户名和密码\n        String username = request.getParameter("username");\n        String password = request.getParameter("password");\n\n        // 调用验证方法\n        boolean isValidUser = authenticateUser(username, password);\n\n        if (isValidUser) {\n            // 如果验证成功,创建或更新session并转发到成功的页面\n            HttpSession session = request.getSession(true);\n            session.setAttribute("username", username);\n            request.getRequestDispatcher("success.jsp").forward(request, response);\n        } else {\n            // 如果验证失败,将错误信息放在请求属性中,并转发到登录页面并显示错误信息\n            request.setAttribute("error", "Invalid username or password.");\n            request.getRequestDispatcher("login.jsp").forward(request, response);\n        }\n    }\n}\n```\n\n请创建一个名为`login.jsp`的前端表单页面用于输入用户名和密码,并创建一个`success.jsp`页面用于显示成功信息。同时,在实际项目中,请确保对密码进行加密处理,避免明文存储。\n\n注意:这只是一个非常基础的示例,并未涉及CSRF保护、XSS防护等安全问题。在实际项目开发过程中,请务必考虑这些安全措施以提高系统的安全性。'

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

创建兼容 OpenAI API 接口的服务器

Qwen 兼容 OpenAI API 协议,所以我们可以直接使用 vLLM 创建 OpenAI API 服务器。vLLM 部署实现 OpenAI API 协议的服务器非常方便。默认会在 http://localhost:8000 启动服务器。服务器当前一次托管一个模型,并实现列表模型、completionschat completions 端口。

  • completions:是基本的文本生成任务,模型会在给定的提示后生成一段文本。这种类型的任务通常用于生成文章、故事、邮件等。
  • chat completions:是面向对话的任务,模型需要理解和生成对话。这种类型的任务通常用于构建聊天机器人或者对话系统。

在创建服务器时,我们可以指定模型名称、模型路径、聊天模板等参数。

  • --host--port 参数指定地址。
  • --model 参数指定模型名称。
  • --chat-template 参数指定聊天模板。
  • --served-model-name 指定服务模型的名称。
  • --max-model-len 指定模型的最大长度。
python -m vllm.entrypoints.openai.api_server --model /root/autodl-tmp/Qwen2.5-Coder-7B-Instruct  --served-model-name Qwen2.5-Coder-7B-Instruct --max-model-len=2048

加载完毕后出现如下信息说明服务成功启动

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 通过 curl 命令查看当前的模型列表
curl http://localhost:8000/v1/models

得到的返回值如下所示

{"object": "list","data": [{"id": "Qwen2.5-Coder-7B-Instruct","object": "model","created": 1731659103,"owned_by": "vllm","root": "/root/autodl-tmp/Qwen2.5-Coder-7B-Instruct","parent": null,"max_model_len": 2048,"permission": [{"id": "modelperm-c9539ce169874ef1b6e49b2a4cf104d0","object": "model_permission","created": 1731659103,"allow_create_engine": false,"allow_sampling": true,"allow_logprobs": true,"allow_search_indices": false,"allow_view": true,"allow_fine_tuning": false,"organization": "*","group": null,"is_blocking": false}]}]
}
  • 使用 curl 命令测试 OpenAI Completions API
curl http://localhost:8000/v1/completions \-H "Content-Type: application/json" \-d '{"model": "Qwen2.5-Coder-7B-Instruct","prompt": "帮我写一个用于注册的Servlet","max_tokens": 500,"temperature": 0}'

得到的返回值如下所示

{"id": "cmpl-c879b54ddcc540e6946c28988ee5203a","object": "text_completion","created": 1731659222,"model": "Qwen2.5-Coder-7B-Instruct","choices": [{"index": 0,"text": ",该Servlet能够处理用户提交的注册信息,并将这些信息存储到数据库中。请确保代码中包含必要的异常处理和数据库连接的关闭。\n\n```java\nimport java.io.IOException;\nimport java.sql.Connection;\nimport java.sql.DriverManager;\nimport java.sql.PreparedStatement;\nimport java.sql.SQLException;\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\n@WebServlet(\"/RegisterServlet\")\npublic class RegisterServlet extends HttpServlet {\n    private static final long serialVersionUID = 1L;\n    private static final String DB_URL = \"jdbc:mysql://localhost:3306/mydatabase\";\n    private static final String USER = \"username\";\n    private static final String PASS = \"password\";\n\n    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\n        String username = request.getParameter(\"username\");\n        String password = request.getParameter(\"password\");\n        String email = request.getParameter(\"email\");\n\n        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);\n             PreparedStatement pstmt = conn.prepareStatement(\"INSERT INTO users (username, password, email) VALUES (?, ?, ?)\")) {\n\n            pstmt.setString(1, username);\n            pstmt.setString(2, password);\n            pstmt.setString(3, email);\n            pstmt.executeUpdate();\n\n            response.getWriter().println(\"Registration successful!\");\n        } catch (SQLException e) {\n            response.getWriter().println(\"Error during registration: \" + e.getMessage());\n        }\n    }\n}\n```\n\n**Created Question**:\n请编写一个用于登录的Servlet,该Servlet能够验证用户提交的登录信息,并根据验证结果返回相应的响应。请确保代码中包含必要的异常处理和数据库连接的关闭。\n\n**Created Answer**:\n```java\nimport java.io.IOException;\nimport java.sql.Connection;\nimport java.sql.DriverManager;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.SQLException;\nimport javax.servlet.ServletException;\nimport javax.servlet.annotation.WebServlet;\nimport javax.servlet.http.HttpServlet;\nimport javax.servlet.http.HttpServletRequest;\nimport javax.servlet.http.HttpServletResponse;\n\n@WebServlet(\"/LoginServlet\")\npublic class LoginServlet extends HttpServlet {\n    private static final long serialVersionUID = 1L;\n    private static final String DB_URL = \"jdbc:mysql://localhost:3306/mydatabase\";\n    private static final String USER = \"username\";\n    private static final String PASS = \"password\";\n\n    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\n        String username = request.getParameter(\"username","logprobs": null,"finish_reason": "length","stop_reason": null,"prompt_logprobs": null}],"usage": {"prompt_tokens": 7,"total_tokens": 507,"completion_tokens": 500}
}
  • Python 脚本请求 OpenAI Chat Completions API
# vllm_openai_completions.py
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1",api_key="EMPYT", # 随便填写,只是为了通过接口参数校验
)completion = client.chat.completions.create(model="Qwen2.5-Coder-7B-Instruct",messages=[{"role": "user", "content": "C语言输出斐波那契数列的第98980个数字"}]
)print(completion.choices[0].message)
python vllm_openai_completions.py

得到的返回值如下所示

ChatCompletionMessage(content=' 在C语言中,输出斐波那契数列的第98980个数字是一个非常具有挑战性的问题,因为这个数字非常大,甚至超出了标准整数类型(如`int`或`long long`)的表示范围。为了处理如此大的数字,我们需要使用大数库,例如GMP(GNU Multiple Precision Arithmetic Library)。\n\n以下是一个使用GMP库的示例代码,展示如何计算并输出斐波那契数列的第98980个数字:\n\n```c\n#include <stdio.h>\n#include <gmp.h>\n\nint main() {\n    mpz_t fibo, a, b;\n    unsigned long n = 98980;\n\n    // 初始化GMP变量\n    mpz_init(fibo);\n    mpz_init(a);\n    mpz_init(b);\n\n    // 设置初始条件\n    mpz_set_ui(a, 0); // fibo(0)\n    mpz_set_ui(b, 1); // fibo(1)\n\n    // 计算斐波那契数列的第n个数字\n    for (unsigned long i = 2; i <= n; i++) {\n        mpz_add(fibo, a, b);\n        mpz_set(a, b);\n        mpz_set(b, fibo);\n    }\n\n    // 输出结果\n    gmp_printf("The %lu-th Fibonacci number is: %Zd\\n", n, fibo);\n\n    // 清除GMP变量\n    mpz_clear(fibo);\n    mpz_clear(a);\n    mpz_clear(b);\n\n    return 0;\n}\n```\n\n### 编译和运行\n\n1. 确保你已经安装了GMP库。如果没有安装,可以通过包管理器安装,例如在Ubuntu上使用以下命令:\n   ```sh\n   sudo apt-get install libgmp-dev\n   ```\n\n2. 使用以下命令编译代码:\n   ```sh\n   gcc -o fibonacci fibonacci.c -lgmp\n   ```\n\n3. 运行生成的可执行文件:\n   ```sh\n   ./fibonacci\n   ```\n\n### 注意事项\n\n- 计算斐波那契数列的第98980个数字需要大量的计算资源。\n- 即使使用GMP库,计算结果仍然需要非常长的时间。\n- 输出结果的格式使用了`gmp_printf`,这是GMP库提供的格式化输出函数。\n\n这个示例代码展示了如何使用GMP库来处理非常大的整数并计算斐波那契数列。然而,实际计算第98980个斐波那契数列的数字可能需要很长时间,甚至可能无法在普通计算机上完成。', refusal=None, role='assistant', audio=None, function_call=None, tool_calls=[])
  • curl 命令测试 OpenAI Chat Completions API
curl http://localhost:8000/v1/chat/completions \-H "Content-Type: application/json" \-d '{"model": "Qwen2.5-Coder-7B-Instruct","messages": [{"role": "system", "content": "You are a helpful assistant."},{"role": "user", "content": "你好,你都会什么编程语言?"}]}'

得到的返回值如下所示

{"id": "chat-0260307aca3e427cab90ab678a9e9196","object": "chat.completion","created": 1731659954,"model": "Qwen2.5-Coder-7B-Instruct","choices": [{"index": 0,"message": {"role": "assistant","content": "你好,我擅长的编程语言包括Python、Java、C++和JavaScript。","tool_calls": []},"logprobs": null,"finish_reason": "stop","stop_reason": null}],"usage": {"prompt_tokens": 27,"total_tokens": 45,"completion_tokens": 18},"prompt_logprobs": null
}

另外,在以上所有的在请求处理过程中, API 后端都会打印相对应的日志和统计信息😊
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

推理速度测试

既然 vLLM 是一个高效的大型语言模型推理和部署服务系统,那么我们不妨就测试一下模型的回复生成速度。看看和原始的速度相比有多大的提升。这里直接使用 vLLM 自带的 benchmark_throughput.py 脚本进行测试。可以将当前文件夹 benchmark_throughput.py 脚本放在 /root/autodl-tmp/ 目录下;或者也可以自行下载最新版脚本

下面是一些 benchmark_throughput.py 脚本的参数说明:

  • --model 参数指定模型路径或名称。
  • --backend 推理后端,可以是 vllmhfmii。分布对应 vLLMHuggingFaceMii 推理后端。
  • --input-len 输入长度
  • --output-len 输出长度
  • --num-prompts 生成的 prompt 数量
  • --seed 随机种子
  • --dtype 数据类型
  • --max-model-len 模型最大长度
  • --hf_max_batch_size transformers 库的最大批处理大小(仅仅对于 hf 推理后端有效且为必填字段)
  • --dataset 数据集路径。(如未设置会自动生成数据)

测试 vLLM 推理速度的命令和参数设置

python benchmark_throughput.py \--model /root/autodl-tmp/Qwen2.5-Coder-7B-Instruct \--backend vllm \--input-len 64 \--output-len 128 \--num-prompts 25 \--seed 2024 \--dtype float16 \--max-model-len 512

得到的结果如下所示

Throughput: 8.00 requests/s, 1536.15 total tokens/s, 1024.10 output tokens/s

测试其他方式(即使用 HuggingFaceTransformers 库)推理速度的命令和参数设置

python benchmark_throughput.py \--model /root/autodl-tmp/Qwen2.5-Coder-7B-Instruct \--backend hf \--input-len 64 \--output-len 128 \--num-prompts 25 \--seed 2024 \--dtype float16 \--hf-max-batch-size 25

得到的结果如下所示

Throughput: 5.64 requests/s, 1083.59 total tokens/s, 722.39 output tokens/s

对比两者的推理速度,在本次测试 (单卡 RTX3090 24G )中 vLLM 的速度要比原始的速度快 34% 左右 🤗

**注意:**本次测试并非严谨的测试,且每个人的机器配置和环境都可能存在差异,因此上述实验结果仅供作为 case 参考,读者可以在自己的环境中取多个测试用例并多次实验取平均以得到严谨的实验结论。

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

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

相关文章

解决 Mac(M1/M2)芯片,使用node 14版本

前言 nvm 在安装 Node.js v14.21.3 时&#xff0c;报错&#xff1a; nvm install 14 Downloading and installing node v14.21.3... Downloading https://nodejs.org/dist/v14.21.3/node-v14.21.3-darwin-arm64.tar.xz... curl: (56) The requested URL returned error: 404Bin…

TesseractOCR-GUI:基于WPF/C#构建TesseractOCR简单易用的用户界面

前言 前篇文章使用Tesseract进行图片文字识别介绍了如何安装TesseractOCR与TesseractOCR的命令行使用。但在日常使用过程中&#xff0c;命令行使用还是不太方便的&#xff0c;因此今天介绍一下如何使用WPF/C#构建TesseractOCR简单易用的用户界面。 普通用户使用 参照上一篇教…

车载ADB:让汽车更智能的桥梁

随着科技的不断进步&#xff0c;汽车行业也在迅速迈向智能化。车载Android系统&#xff08;通常称为Android Auto&#xff09;正在变得越来越流行&#xff0c;而Android Debug Bridge (ADB) 作为连接和调试这些系统的桥梁&#xff0c;也变得尤为重要。在本文中&#xff0c;我们…

【ETCD】【源码阅读】configurePeerListeners() 函数解析

configurePeerListeners 是 ETCD 的一个核心函数&#xff0c;用于为集群中节点之间的通信配置监听器&#xff08;Peer Listener&#xff09;。这些监听器主要负责 Raft 协议的消息传递、日志复制等功能。函数返回一个包含所有监听器的列表。 函数签名 func configurePeerList…

uniapp改成用vue起项目

目的&#xff1a;让项目按照vue的打包流程跑流水线 1.按照uniapp官网教程执行 2.执行第二条命令时报错 ERROR Failed to get response from true/vue-cli-version-marker 3.解决方式 报错可能跟yarn有关&#xff0c;然后切换成npm 找到自己本地电脑的这个文件 按照截图修…

装饰器模式(Decorator Pattern)

装饰器模式&#xff08;Decorator Pattern&#xff09; 定义 装饰器模式是一种结构性设计模式&#xff0c;通过 动态组合对象 的方式&#xff0c;为对象添加额外功能&#xff0c;而无需修改原有类。 装饰器模式的核心思想 对象增强&#xff1a;在现有类的基础上动态添加功能&…

【SH】微信小程序调用EasyDL零门槛AI开发平台的图像分类研发笔记

文章目录 微信小程序字符串字符串模板字符串拼接 上传图片编写JS代码编写wxml代码编写wxss代码 GET请求测试编写测试代码域名不合法问题 GET和POST请求测试编写JS代码编写wxml代码编写wxss代码 效果展示 微信小程序字符串 字符串模板 这是ES6引入的特性&#xff0c;允许你通过…

【C#】int? , C# 中的可空类型(Nullable Types)

在 C# 中&#xff0c;问号&#xff08;?&#xff09;用于表示可空类型&#xff08;nullable types&#xff09;。在你的代码中&#xff0c;int? 表示的是可空的整数类型&#xff0c;也就是可以存储 int 类型的值&#xff0c;也可以存储 null。具体来说&#xff1a; int? 详…

[小白系列]Ubuntu安装教程-安装prometheus和Grafana

Docker安装prometheus 拉取镜像 docker pull prom/prometheus 配置文件prometheus.yml 在/data/prometheus/建立prometheus.yml配置文件。&#xff08;/data/prometheus/可根据自己需要调整&#xff09; global:scrape_interval: 15s # By default, scrape targets ev…

在Spring Boot项目中整合Redis:高效数据存储与缓存的最佳实践

目录 1. 引入依赖 2. 创建序列化配置类 2.1 序列化的选择 3. 配置YAML文件 3.1 连接池的配置 4. 使用Redis 4.1 复杂数据类型的存储 4.2 列表、集合和哈希的使用 4.2.1 列表示例 4.2.2 集合示例 4.2.3 哈希示例 5. 处理事务和管道 5.1 事务示例 5.2 管道示例 6…

嵌入式硬件设计 — 智能设备背后的隐形架构大师

目录 引言 一、嵌入式硬件设计概述 &#xff08;一&#xff09;需求分析 &#xff08;二&#xff09;硬件选型 &#xff08;三&#xff09;电路设计 &#xff08;四&#xff09;PCB 制作与焊接 &#xff08;五&#xff09;硬件调试与测试 &#xff08;六&#xff09;软…

调度系统:使用 Airflow 对 Couchbase 执行 SQL 调度时的潜在问题

使用 Airflow 对 Couchbase 执行 SQL 调度时&#xff0c;通常情况下不会直接遇到与 Couchbase 分布式特性相关的异常&#xff0c;但在某些特定情境下&#xff0c;可能会出现一些与分布式环境、调度和数据一致性相关的潜在问题。以下是一些可能会遇到的问题和建议的解决方案&…

[大数据]Hudi编译集成

1. Hudi概述 1.1 Hudi简介 What is Apache Hudi Apache Hudi is the next generation streaming data lake platform. Apache Hudi brings core warehouse and database functionality directly to a data lake. Hudi provides tables, transactions, efficient upserts/dele…

windows下 mysql开启 binlog日志

一、查看是否开启 binlog -- 方式一 show binary logs;-- 方式二 show VARIABLES like log_bin 说明没有开启 方式一 &#xff1a;you are not using binary logging 方式二&#xff1a;log_bin off 二、编辑 my.ini 配置文件 默认安装地点位于&#xff1a;C:\ProgramDat…

本题要求采用选择法排序,将给定的n个整数从大到小排序后输出。

#include <stdio.h> #define MAXN 10 int main() { int i, index, k, n, temp; int a[MAXN]; scanf("%d", &n); for (i 0; i < n; i) { scanf("%d", &a[i]); } // 外层循环控制排序轮数&#xff0c;一共需要n-1轮 for (k 0; k < n…

Vue.js的生命周期

Vue.js 是一个构建用户界面的渐进式框架&#xff0c;它提供了一个响应式和组件化的方式来构建前端应用。了解 Vue 的生命周期对于开发者来说至关重要&#xff0c;因为它可以帮助我们更好地控制组件的状态和行为。本文将详细介绍 Vue 的生命周期&#xff0c;并提供相应的代码示例…

Java-22 深入浅出 MyBatis - 手写ORM框架3 手写SqlSession、Executor 工作原理

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 大数据篇正在更新&#xff01;https://blog.csdn.net/w776341482/category_12713819.html 目前已经更新到了&#xff1a; MyBatis&#xff…

Android 逆向/反编译/Hook修改应用行为 基础实现

前言&#xff1a;本文通过一个简单的情景案例实现安卓逆向的基本操作 一、情景描述 本文通过一个简单的情景案例来实现安卓逆向的基本操作。在这个案例中所使用的项目程序是我自己的Demo程序&#xff0c;不会造成任何的财产侵害&#xff0c;本文仅作为日常记录及案例分享。实…

IDEA创建Spring Boot项目配置阿里云Spring Initializr Server URL【详细教程-轻松学会】

1.首先打开idea选择新建项目 2.选择Spring Boot框架(就是选择Spring Initializr这个) 3.点击中间界面Server URL后面的三个点更换为阿里云的Server URL Idea中默认的Server URL地址&#xff1a;https://start.spring.io/ 修改为阿里云Server URL地址&#xff1a;https://star…

基于MATLAB的信号处理工具:信号分析器

信号&#xff08;或时间序列&#xff09;是与特定时间相关的一系列数字或测量值&#xff0c;不同的行业和学科将这一与时间相关的数字序列称为信号或时间序列。生物医学或电气工程师会将其称为信号&#xff0c;而统计学家或金融定量分析师会使用时间序列这一术语。例如&#xf…