大模型推理--Qwen2.5-Omni在A100上的初体验

news2025/4/18 17:09:11

过去的一周Qwen2.5-Omni产生了很高的热度,吸引了很多人的目光。它的多模态确实很吸引人,放出来的demo体验还算尚可(语音对话的延迟还是太大),所以就在A100 PCIe上实地部署了一下,初步对其速度进行了测试,以下是我的操作流程,供大家参考。

1.资源下载

1.1 下载git项目

首先下载官方git项目:

git clone https://github.com/QwenLM/Qwen2.5-Omni

该git没有太多有价值的资源,主要就是一个docker部署文件和一个web_demo,不过后续的流程基本都参考该git的readme实现,所以大家可以clone下来之后仔细研读readme。

1.2 下载模型文件

上面的git项目建议大家从魔塔社区下载,所以我就从modelscope进行了下载,命令如下:

pip install modelscope
modelscope download --model Qwen/Qwen2.5-Omni-7B

因为模型较大,下载时间估计在1小时以上,请慢慢等待。下载的模型可以放在上一步的git项目中。

2.环境配置

运行大模型除了显卡跑不起来之外,最麻烦的事情可能就是环境配置,往往需要折腾半天以上。幸好上面的git项目中提供了一个官方docker避免了我们自己搭建环境,个人建议就是直接使用该docker镜像,否则你会遇到很多麻烦,就像我一样。此外,官方还提供了一个Dockerfile,大家也可以采用该文件去手动构建可用的docker镜像。在此,我还是把自己的构建过程分享给大家,让大家在遇到相同问题时能不慌。

2.1 创建Docker容器

执行以下命令:

docker container  run --net=host -v ~/Qwen2.5-Omni/:/workspace/Qwen2.5-Omni/ -it -d --name qwen2.5-omni --gpus device=7 cu12_torch250:1.0
docker container start 1602a
docker container exec -it 1602a bash

上述三条命令在后台创建一个容器,占用id为7的A100显卡,用的镜像叫cu12_torch250,这个镜像是我自己之前构造的,不是官方镜像。为了能长期使用该容器,我一般通过-d在后台启动,然后通过exec进入容器。退出容器通过ctrl+p加ctrl+q实现。

2.2 配置容器内软件环境

参照git中的readme卸载已安装的transformers库,并从源码安装特定版本的transformers库,执行如下命令:

pip uninstall transformers
pip install git+https://github.com/huggingface/transformers@f742a644ca32e65758c3adb36225aef1731bd2a8
pip install accelerate
pip install qwen-omni-utils[decord]

执行完第二步之后,pip list查看transformers版本为4.50.0.dev0。特别注意一点,第二步给出的版本号要仔细查看,git上的readme貌似给了两个不同的版本,有一个是不可用的。

在我的docker容器内,执行完第4步会提示:

ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.
cugraph 23.12.0 requires cudf==23.12.*, which is not installed.
cugraph 23.12.0 requires dask-cudf==23.12.*, which is not installed.
cugraph-service-server 23.12.0 requires cudf==23.12.*, which is not installed.
cugraph-service-server 23.12.0 requires dask-cudf==23.12.*, which is not installed.
cuml 23.12.0 requires cudf==23.12.*, which is not installed.
cuml 23.12.0 requires dask-cudf==23.12.*, which is not installed.
dask-cuda 23.12.0 requires pynvml<11.5,>=11.0.0, which is not installed.

不过在后续的操作中没有用到报错的软件,所以我也没有去修复该错误。

官方git还建议按照flash-attn用来加速推理,命令如下:

pip install -U flash-attn --no-build-isolation

不过安装完之后flash-attn的版本应该是2.7.4.post1。但是我之前已经安装过2.7.2.post1,所以就没有再重新安装。后续速度测试的时候还会提到flash-attn。

3. Web demo跑通

3.1 安装缺失的软件

可以直接用git中的requirements.txt来一键安装所有软件,不过大部分软件我都已经安装,为了不破坏原有安装软件的版本,我只安装了缺失的两个软件:

pip install gradio
pip install modelscope_studio

3.2 运行demo

启动命令为:

python web_demo.py --flash-attn2 --server-name '10.192.2.1'

在我的docker容器内,如果不加–flash-attn2则无法正常启动。启动之后提示可以通过http://10.192.2.1:7860/访问网页。但是打开网页之后,摄像头、麦克风均因为网页不安全没有使用权限,只能通过offline页面上传音频文件进行体验。我上传了一个不到4s的音频文件,在经过十几秒的等待之后给我返回了结果。这个速度着实是慢的离谱啊!与魔塔和HF上相同的demo速度相比差得太远了。我又连续上传了几个音频文件,后台提示最后一轮推理的输入为:

[{‘role’: ‘system’, ‘content’: ‘You are Qwen, a virtual human developed by the Qwen Team, Alibaba Group, capable of perceiving auditory and visual inputs, as well as generating text and speech.’}, {‘role’: ‘user’, ‘content’: [{‘type’: ‘audio’, ‘audio’: ‘/tmp/gradio/af6e0/test.wav’}]}, {‘role’: ‘assistant’, ‘content’: ‘嗯,那你好好洗个澡哈。洗完澡咱们再聊,有啥事儿都可以跟我说哦。’}, {‘role’: ‘user’, ‘content’: [{‘type’: ‘audio’, ‘audio’: ‘/tmp/gradio/4d4f8ecdb21/output5.wav’}]}, {‘role’: ‘assistant’, ‘content’: ‘中国最长的河流是长江。它全长约6300千米呢。你要是还想知道关于长江或者其他河流的事儿,可以再问我呀。’}, {‘role’: ‘user’, ‘content’: [{‘type’: ‘audio’, ‘audio’:‘/tmp/gradio/f57e72267b/output6.wav’}]}, {‘role’: ‘assistant’,‘content’: ‘我是阿里云研发的大规模语言模型,我叫通义千问,有什么我可以帮助你的吗?’}, {‘role’: ‘user’,‘content’: [{‘type’: ‘audio’, ‘audio’:‘/tmp/gradio/b83b0b07986/question.wav’}]}]

可以看出,它的多轮机制就是通过把之前的历史保留下来重复送给大模型推理实现的。这里有一个很大的问题,如果不做prefix Cache,历史会越来越长,推理速度也会越来越慢,不确定https://chat.qwen.ai/这个网址是如何实现的多轮。

这里还有另外一个疑问,因为还没有看过相关源码,所以不确定上述prompt中前几轮的wav文件会如何处理:是保持文本状态就一个单纯的文件链接,还是也会再提取音频的embedding信息。如果还会提取embedding信息,感觉重复计算又来了,如果不提取则感觉一个单纯的文件链接也没有什么意义。

4.速度测试

4.1 原始demo

鉴于3中的web_demo速度实在太慢了,所以我又仿照git中的示例代码在本地进行了速度验证。Demo代码如下:

import time
import torch
import soundfile as sf

from transformers import Qwen2_5OmniModel, Qwen2_5OmniProcessor
from qwen_omni_utils import process_mm_info

# default: Load the model on the available device(s)
model = Qwen2_5OmniModel.from_pretrained("Qwen2.5-Omni-7B", torch_dtype="auto", device_map="auto", enable_audio_output=True)

# 我们建议启用 flash_attention_2 以获取更快的推理速度以及更低的显存占用.
#model = Qwen2_5OmniModel.from_pretrained("Qwen2.5-Omni-7B", torch_dtype=torch.bfloat16, device_map="auto", attn_implementation="flash_attention_2", enable_audio_output=False)

processor = Qwen2_5OmniProcessor.from_pretrained("Qwen2.5-Omni-7B")

conversation = [
    {
        "role": "system",
        "content": "You are Qwen, a virtual human developed by the Qwen Team, Alibaba Group, capable of perceiving auditory and visual inputs, as well as generating text and speech.",
    },
    {
        "role": "user",
        "content": [
            {"type": "audio", "audio": "wav/test1.wav"},
        ],
    },
]

# set use audio in video
USE_AUDIO_IN_VIDEO = True

# Preparation for inference
s = time.time()
text = processor.apply_chat_template(conversation, add_generation_prompt=True, tokenize=False)
audios, images, videos = process_mm_info(conversation, use_audio_in_video=USE_AUDIO_IN_VIDEO)
inputs = processor(text=text, audios=audios, images=images, videos=videos, return_tensors="pt", padding=True, use_audio_in_video=USE_AUDIO_IN_VIDEO)
inputs = inputs.to(model.device).to(model.dtype)
e = time.time()
print(f'prepare time: {(e-s)*1000:.2f}ms')

# Inference: Generation of the output text and audio
text_ids, audio = model.generate(**inputs, use_audio_in_video=USE_AUDIO_IN_VIDEO, return_audio=True)
s = time.time()
print(f'generate time: {(s-e)*1000:.2f}ms')
print(text_ids)

text = processor.batch_decode(text_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)
e = time.time()
print(f'batch_decode time: {(e-s)*1000:.2f}ms')
print(text)

sf.write(
    "output.wav",
    audio.reshape(-1).detach().cpu().numpy(),
    samplerate=24000,
)

在上面的代码中我们暂时没有使用flash-attn进行加速,然后通过enable_audio_output=True来选择合成音频。还是web_demo测试时不到4s的音频文件,运行上述demo会打印: prepare time: 943ms, generate time: 11723ms,这个推理速度基本和web_demo一致,太慢了。

然后设置enable_audio_output=False,generate的参数设置return_audio=False来避免生成音频文件,则generate速度就可以由11.7s降低到1.7s。这说明推理耗时的大头都被TTS模块给占据了,不做TTS可以大幅提升推理速度。

4.2 stream demo

原始的demo中,一个4s不到的音频generate时间为1.7s,这个速度够快吗?我感觉还是挺慢的。所以我把原始demo改成流式输出,看看Qwen2.5生成每个token的速度有多快。Stream demo代码如下:

import time
import torch
import datetime
import builtins
import soundfile as sf
from threading import Thread

from transformers import Qwen2_5OmniModel, Qwen2_5OmniProcessor, AutoTokenizer, TextIteratorStreamer
from qwen_omni_utils import process_mm_info

def custom_print(*args, **kwargs):
    current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
    original_print(f'[{current_time}]', *args, **kwargs)


# change print function to add time stamp
original_print = builtins.print
builtins.print = custom_print

# default: Load the model on the available device(s)
model = Qwen2_5OmniModel.from_pretrained("Qwen2.5-Omni-7B", torch_dtype="auto", device_map="auto", enable_audio_output=False)

# 我们建议启用 flash_attention_2 以获取更快的推理速度以及更低的显存占用.
#model = Qwen2_5OmniModel.from_pretrained("Qwen2.5-Omni-7B", torch_dtype=torch.bfloat16, device_map="auto", attn_implementation="flash_attention_2", enable_audio_output=False)

processor = Qwen2_5OmniProcessor.from_pretrained("Qwen2.5-Omni-7B")
tokenizer = AutoTokenizer.from_pretrained("Qwen2.5-Omni-7B")
streamer = TextIteratorStreamer(tokenizer)

conversation = [
    {
        "role": "system",
        "content": "You are Qwen, a virtual human developed by the Qwen Team, Alibaba Group, capable of perceiving auditory and visual inputs, as well as generating text and speech.",
    },
    {
        "role": "user",
        "content": [
            {"type": "audio", "audio": "wav/test1.wav"},
        ],
    },
]

# set use audio in video
USE_AUDIO_IN_VIDEO = True

# Preparation for inference
s = time.time()
text = processor.apply_chat_template(conversation, add_generation_prompt=True, tokenize=False)
audios, images, videos = process_mm_info(conversation, use_audio_in_video=USE_AUDIO_IN_VIDEO)
inputs = processor(text=text, audios=audios, images=images, videos=videos, return_tensors="pt", padding=True, use_audio_in_video=USE_AUDIO_IN_VIDEO)
inputs = inputs.to(model.device).to(model.dtype)
e = time.time()
print(f'prepare time: {(e-s)*1000:.2f}ms')

# Inference: Generation of the output text and audio
generation_kwargs = {
    'streamer':streamer,
    'use_audio_in_video':USE_AUDIO_IN_VIDEO,
    'return_audio':False,
    **inputs
}
thread = Thread(target=model.generate, kwargs=generation_kwargs)
thread.start()
for token in streamer:
    print(token)

上述demo和原始demo类似,但是通过TextIteratorStreamer来实现逐token生成。另外,我修改了一下print,让它打印一下时间,重新跑一下会生成如下输出:

[2025-04-03 09:06:07.465][2025-04-03 09:06:07.542]
[2025-04-03 09:06:07.577] ,那你
[2025-04-03 09:06:07.610] 好好
[2025-04-03 09:06:07.644][2025-04-03 09:06:07.679][2025-04-03 09:06:07.727][2025-04-03 09:06:07.769][2025-04-03 09:06:07.808]
[2025-04-03 09:06:07.847] 。洗
[2025-04-03 09:06:07.886][2025-04-03 09:06:07.924][2025-04-03 09:06:07.963] 咱们
[2025-04-03 09:06:08.001][2025-04-03 09:06:08.034][2025-04-03 09:06:08.067]
[2025-04-03 09:06:08.108] ,有
[2025-04-03 09:06:08.151][2025-04-03 09:06:08.194] 事儿
[2025-04-03 09:06:08.228] 都可以
[2025-04-03 09:06:08.262] 跟我说
[2025-04-03 09:06:08.295][2025-04-03 09:06:08.329]
[2025-04-03 09:06:08.362]
[2025-04-03 09:06:08.363]<|im_end|>

通过分析每两行之间的时间差,大概可以知道每个token的生成时间大概为30~40ms左右,也即每秒大概生成2、30个token。我感觉这个速度还是挺慢的。

4.3 batch demo

官方git中提到,在不生成音频的情况下,还可以通过batch的方式进行推理。我又仿照官方给出的示例代码写了一个batch demo,代码如下:

import time
import torch
import soundfile as sf

from transformers import Qwen2_5OmniModel, Qwen2_5OmniProcessor
from qwen_omni_utils import process_mm_info

# default: Load the model on the available device(s)
model = Qwen2_5OmniModel.from_pretrained("Qwen2.5-Omni-7B", torch_dtype="auto", device_map="auto", enable_audio_output=False)

# 我们建议启用 flash_attention_2 以获取更快的推理速度以及更低的显存占用.
#model = Qwen2_5OmniModel.from_pretrained("Qwen2.5-Omni-7B", torch_dtype=torch.bfloat16, device_map="auto", attn_implementation="flash_attention_2", enable_audio_output=False)

processor = Qwen2_5OmniProcessor.from_pretrained("Qwen2.5-Omni-7B")

conversation1 = [
    {
        "role": "system",
        "content": "You are Qwen, a virtual human developed by the Qwen Team, Alibaba Group, capable of perceiving auditory and visual inputs, as well as generating text and speech.",
    },
    {
        "role": "user",
        "content": [
            {"type": "audio", "audio": "wav/test1.wav"},
        ],
    },
]

conversation2 = [
    {
        "role": "system",
        "content": "You are Qwen, a virtual human developed by the Qwen Team, Alibaba Group, capable of perceiving auditory and visual inputs, as well as generating text and speech.",
    },
    {
        "role": "user",
        "content": [
            {"type": "audio", "audio": "wav/test2.wav"},
        ],
    },
]

conversation3 = [
    {
        "role": "system",
        "content": "You are Qwen, a virtual human developed by the Qwen Team, Alibaba Group, capable of perceiving auditory and visual inputs, as well as generating text and speech.",
    },
    {
        "role": "user",
        "content": [
            {"type": "audio", "audio": "wav/test3.wav"},
        ],
    },
]

conversation4 = [
    {
        "role": "system",
        "content": "You are Qwen, a virtual human developed by the Qwen Team, Alibaba Group, capable of perceiving auditory and visual inputs, as well as generating text and speech.",
    },
    {
        "role": "user",
        "content": [
            {"type": "audio", "audio": "wav/test4.wav"},
        ],
    },
]

conversation5 = [
    {
        "role": "system",
        "content": "You are Qwen, a virtual human developed by the Qwen Team, Alibaba Group, capable of perceiving auditory and visual inputs, as well as generating text and speech.",
    },
    {
        "role": "user",
        "content": [
            {"type": "audio", "audio": "wav/test5.wav"},
        ],
    },
]

conversations=[conversation1, conversation2, conversation3, conversation4, conversation5]

# set use audio in video
USE_AUDIO_IN_VIDEO = True

# Preparation for inference
s = time.time()
text = processor.apply_chat_template(conversations, add_generation_prompt=True, tokenize=False)
audios, images, videos = process_mm_info(conversations, use_audio_in_video=USE_AUDIO_IN_VIDEO)
inputs = processor(text=text, audios=audios, images=images, videos=videos, return_tensors="pt", padding=True, use_audio_in_video=USE_AUDIO_IN_VIDEO)
inputs = inputs.to(model.device).to(model.dtype)
e = time.time()
print(f'prepare time: {(e-s)*1000:.2f}ms')

# Inference: Generation of the output text and audio
text_ids = model.generate(**inputs, use_audio_in_video=USE_AUDIO_IN_VIDEO, return_audio=False)
s = time.time()
print(f'generate time: {(s-e)*1000:.2f}ms')
print(text_ids)

text = processor.batch_decode(text_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)
e = time.time()
print(f'batch_decode time: {(e-s)*1000:.2f}ms')
print(text)

在上述代码中,我将5个长度在1~4s之间的音频文件一起灌给Qwen2.5-Omni进行推理,prepare的耗时大概在2.2s,generate的时间大概在4.4s。这个速度肯定比顺序算5个文件要快,但是整体的速度还是很慢。大概就是:5个4s的音频文件batch推理需要7s,这根本就无法用在实时的环境下,只适合离线场景。

5.推理加速

目前我还没有跑通官方给出的两种加速思路:flash-attn和vLLM,后续跑通会及时更新,先把我的教训分享给大家。

5.1 flash-attn

前面提到我没有按照官方的要求安装最新版的flash-attn,因为之前已经安装过一次。上一节给出的demo中在加载模型时有对应的flash-attn支持,但是我试用了一下发现速度根本没有变化,不知道是咋回事。然后我又尝试利用命令pip install -U flash-attn --no-build-isolation安装最新版的flash-attn,但是安装过程极为漫长,我都下班了也没有安装完,遂杀了下周重试。

5.2 vLLM

官方还给出了vLLM示例。但是用的vLLM版本不是主版本,所以需要我们自己进行源码编译。编译命令如下:

git clone -b qwen2_omni_public_v1 https://github.com/fyabc/vllm.git
cd vllm
pip install .

看着很简单,但是你一执行就会发现此路根本行不通。问题出在哪呢?就出在安装过程特别漫长,占用资源特别巨大,你一个不注意就把你机器整崩了。首先,当安装过程提示Installing build dependencies时,你要耐心等待,该步骤会耗时3个小时以上。其次,当上述步骤完成之后,还会触发torch2.6.0和transformers4.50.3等一系列软件的更新,如果安装完毕就会导致你的docker容器环境大变样。更为恶心的是,更新了transformers库又把上面刚新装的transformers库给覆盖了,上述demo变得无法跑通,还得按照前面提到的流程更新transformers库,幸好我没有安装成功。最后,当安装进行到最后一步Building wheels for collected packages,你要及时打开你的top命令,你就会发现你的所有核都被占满了,内存也在慢慢增长。我用的服务器内存是500G,结果一会不到就全部占满了。之前安装flash-attn的时候也经历过一次,当时的后果就是服务器挂了被迫重启。所以这次在安装vLLM的时候当内存快爆掉的时候我就把它杀了,最终也没有成功安装vLLM。

所以,最好的方式还是要使用官方的docker镜像,等有了新的实验结果及时同步给大家。

6.疑问

我看魔塔和git上的issue累积越来越多,感觉是官方一下子被整懵了。我个人觉得现在放出来的这个Qwen2.5-Omni有点仓促上马的意味,相当不完善。有很多人也包括我都有一个疑问:为什么https://chat.qwen.ai/给出的demo可以比较好的支持流式对话(当然延迟比较大,一般在2~4s),但是HF和魔塔上给出的demo却是需要上传文件的形式?如何实现纯粹的流式推理?毕竟上传文件这种形式在实际中没有太大意义。另一个疑问,为什么我自己用A100搭建的web_demo速度这么慢,与HF和魔塔上的速度对比差异太大了,官方最好能给一个比较明确的运行方式和硬件配置。还有,我自己测试flash-attn速度没有变化,这个是和我安装的flash-attn不是最新版有关吗?最后,Qwen2.5-Omni的多轮是如何实现的,如何避免prompt重复推理的?

不知道大家有没有发现,Freeze-Omni的作者wang xiong也是Qwen2.5-Omni的作者。理论上,Qwen2.5-Omni应该可以比较快得具有Freeze-Omni那样的流式推理能力(我怀疑https://chat.qwen.ai/这个网址就是按照Freeze-Omni那样实现的)。Freeze-Omni这个项目挺好的,但是是基于Qwen2做的,所以效果要比Qwen2.5-Omni略差,期待wang xiong大佬能快速开源一个新版的Freeze-Omni。Freeze-Omni的另一个问题是成本太高了,单卡单用户,根本无法上线。Qwen2.5-Omni相比Freeze-Omni效果有提升,但是也不完美,它的知识可能和Qwen2是一样的,比较老旧。我问了他一个问题:特朗普还是美国总统吗?它回答不是了。所以基本上来说,Qwen2.5-Omni也还属于一个玩具,无法与线上几十B的大模型效果相匹配,希望这个月发布的Qwen3能大幅提升文本效果。

紧跟着Qwen2.5-Omni的发布,百度也发布了自己的端到端语音大模型,号称双L20卡的并发可以做到几百以上,如果真是如此那端到端语音大模型终于迎来了商业落地的重大时刻。不过根据百度以往的习惯,他们的技术都不开源,基本属于自嗨的一种状态,业界也没有人真正去follow。希望李彦宏这次被Deepseek刺激之后,往后多多开源,让我们这些小企业能真正受益。

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

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

相关文章

CExercise_07_1指针和数组_2数组元素的逆序数组逆序(指针版 reverse_by_ptr 和下标版 reverse_arr)

题目&#xff1a; 数组元素的逆序。要求使用[]运算符以及纯粹指针操作两种方式来完成。 关键点 arr[i] arr[len - 1 - i]; arr[0]arr[len-1]; 如果数组序列是偶数,则调换最中间一对为止;若为奇数,则单出一个不用反转. 思想就是长度取一半 eg:8/2, 9/24.5,反转一半,到5时固定…

框架PasteForm实际开发案例,换个口味显示数据,支持echarts,只需要标记几个特性即可在管理端显示(2)

PasteForm框架的主要思想就是对Dto进行标记特性,然后管理端的页面就会以不一样的UI呈现 使用PasteForm框架开发,让你免去开发管理端的烦恼,你只需要专注于业务端和用户端! 在管理端中,如果说表格是基本的显示方式,那么图表chart就是一个锦上添花的体现! 如果一个项目拥…

Starrocks的Bitmap索引和Bloom filter索引以及全局字典

写这个的主要作用是梳理一下Starrocks的索引效率以及使用场景。 Starrocks Bitmap索引 原理&#xff1a; Bitmap 索引是一种使用 bitmap 的特殊数据库索引。bitmap 即为一个 bit 数组&#xff0c;一个 bit 的取值有两种&#xff1a;0 或 1。 每一个 bit 对应数据表中的一行&…

QML面试笔记--UI设计篇05容器控件

1. QML中容器控件全解&#xff1a;构建灵活界面的基石 1.1. Item&#xff08;万物容器&#xff09;1.2. Rectangle&#xff08;视觉容器&#xff09;1.3. ListView&#xff08;动态列表容器&#xff09;1.4. Frame&#xff08;表单容器&#xff09;1.5. SwipeView&#xff08;页…

VSCode运行,各类操作缓慢,如何清理

VSCode写代码&#xff0c;随着项目逐步进展&#xff0c;代码量在增加&#xff0c;依赖的第三方头文件也在增加&#xff0c; 先是发现代码提示的速度变慢&#xff0c; 后来格式化代码速度太慢 然后c/c代码的语法检查有时候压根就失败&#xff0c;来个错误提示 还有source contro…

redis(2)-mysql-锁

1.数据倾斜&#xff1a; 解决&#xff1a;虚拟节点 2.缓存穿透&#xff1a;缓存雪崩、击穿 3.分布式锁 多把锁控制不同节点上的一致性问题。 锁是有失效时间的。 强制回收。 4.redis 和zookeeper的区别 redis 数据支持有效期 4.1 zookeeper 分布式一致性服务框架&am…

OpenLayers:海量图形渲染之矢量切片

最近由于在工作中涉及到了海量图形渲染的问题&#xff0c;因此我开始研究相关的解决方案。在咨询了许多朋友之后发现矢量切片似乎是行业内最常用的一种解决方案&#xff0c;于是我便开始研究它该如何使用。 一、什么是矢量切片 矢量切片按照我的理解就是用栅格切片的方式把矢…

AI智算-K8s+vLLM Ray:DeepSeek-r1 671B 满血版分布式推理部署实践

K8s + vLLM & Ray:DeepSeek-r1 671B 满血版分布式推理部署实践 前言环境准备1. 模型下载2. 软硬件环境介绍正式部署1. 模型切分2. 整体部署架构3. 安装 LeaderWorkerSet4. 通过 LWS 部署DeepSeek-r1模型5. 查看显存使用率6. 服务对外暴露7. 测试调用API7.1 通过 curl7.2 通…

深入浅出SPI通信协议与STM32实战应用(W25Q128驱动)(实战部分)

1. W25Q128简介 W25Q128 是Winbond推出的128M-bit&#xff08;16MB&#xff09;SPI接口Flash存储器&#xff0c;支持标准SPI、Dual-SPI和Quad-SPI模式。关键特性&#xff1a; 工作电压&#xff1a;2.7V~3.6V分页结构&#xff1a;256页/块&#xff0c;每块16KB&#xff0c;共1…

前端知识点---闭包(javascript)

文章目录 1.怎么理解闭包?2.闭包的特点3.闭包的作用?4 闭包注意事项&#xff1a;5 形象理解6 闭包的应用 1.怎么理解闭包? 函数里面包着另一个函数&#xff0c;并且内部函数可以访问外部函数的变量。 <script> function box() {//周围状态&#xff08;外部函数中定义的…

Java 泛型的逆变与协变:深入理解类型安全与灵活性

泛型是 Java 中强大的特性之一&#xff0c;它提供了类型安全的集合操作。然而&#xff0c;泛型的类型关系&#xff08;如逆变与协变&#xff09;常常让人感到困惑。 本文将深入探讨 Java 泛型中的逆变与协变&#xff0c;帮助你更好地理解其原理和应用场景。 一、什么是协变与…

多线程(进阶)(内涵面试题)

目录 一、常见的锁策略 1. 悲观锁 vs 乐观锁 2. 重量级锁 vs 轻量级锁 3. 挂起等待锁 vs 自旋锁 4. 普通互斥锁 vs 读写锁 5. 可重入锁 vs 不可重入锁 6. 公平锁 vs 非公平锁 7. 面试题 二、synchronized的原理 1. 基本特点 2. 加锁工作过程 1&#xff09;偏向锁&am…

蓝桥杯补题

方法技巧&#xff1a; 1.进行循环暴力骗分&#xff0c;然后每一层的初始进行判断&#xff0c;如果已经不满足题意了&#xff0c;那么久直接continue&#xff0c;后面的循环就不用浪费时间了。我们可以把题目所给的等式&#xff0c;比如说有四个未知量&#xff0c;那么我们可以用…

【MySQL篇】mysqlpump和mysqldump参数区别总汇

&#x1f4ab;《博主主页》&#xff1a;奈斯DB-CSDN博客 &#x1f525;《擅长领域》&#xff1a;擅长阿里云AnalyticDB for MySQL(分布式数据仓库)、Oracle、MySQL、Linux、prometheus监控&#xff1b;并对SQLserver、NoSQL(MongoDB)有了解 &#x1f496;如果觉得文章对你有所帮…

SQL:DDL(数据定义语言)和DML(数据操作语言)

目录 什么是SQL&#xff1f; 1. DDL&#xff08;Data Definition Language&#xff0c;数据定义语言&#xff09; 2. DML&#xff08;Data Manipulation Language&#xff0c;数据操作语言&#xff09; DDL和DML的区别 什么是SQL&#xff1f; SQL&#xff08;Structured …

神舟平板电脑怎么样?平板电脑能当电脑用吗?

在如今的数码产品市场上&#xff0c;神舟平板电脑会拥有独特的优势&#xff0c;其中比较受到大家关注的就是神舟PCpad为例&#xff0c;无论是设计还是规格也会有很多的亮点&#xff0c;那么是不是可以直接当成电脑一起来使用呢&#xff1f; 这款平板电脑就会配备10.1英寸显示屏…

【力扣hot100题】(075)数据流的中位数

一开始只建立了一个优先队列&#xff0c;每次查询中位数时都要遍历一遍于是喜提时间超限&#xff0c;看了答案才恍然大悟原来还有这么聪明的办法。 方法是建立两个优先队列&#xff0c;一个大根堆一个小根堆&#xff0c;大根堆记录较小的数&#xff0c;小根堆记录较大的数。 …

Java——pdf增加水印

文章目录 前言方式一 itextpdf项目依赖引入编写PDF添加水印工具类测试效果展示 方式二 pdfbox依赖引入编写实现类效果展示 扩展1、将inputstream流信息添加水印并导出zip2、部署出现找不到指定字体文件 资料参考 前言 近期为了知识库文件导出&#xff0c;文件数据安全处理&…

leetcode_19. 删除链表的倒数第 N 个结点_java

19. 删除链表的倒数第 N 个结点https://leetcode.cn/problems/remove-nth-node-from-end-of-list/ 1、题目 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#…

41、web前端开发之Vue3保姆教程(五 实战案例)

一、项目简介和需求概述 1、项目目标 1.能够基于Vue3创建项目 2.能够基本Vue3相关的技术栈进行项目开发 3.能够使用Vue的第三方组件进行项目开发 4.能够理解前后端分离的开发模式 2、项目概述 使用Vue3结合ElementPlus,ECharts工具实现后台管理系统页面,包含登录功能,…