第N8周:使用Word2vec实现文本分类
文章目录
- 一、数据预处理
- 1.加载数据
- 2.构建词典
- 3.生成数据批次和迭代器
- 二、模型构建
- 1.搭建模型
- 2.初始化模型
- 3.定义训练与评估函数
- 三、训练模型
- 1.拆分数据集并运行模型
- 四、总结
- 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
- 🍖 原作者:K同学啊
一、数据预处理
1.加载数据
import torch
import torch.nn as nn
import torchvision
from torchvision import transforms, datasets
import os, PIL, pathlib, warningswarnings.filterwarnings("ignore")device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
device
device(type=‘cpu’)
import pandas as pd # 加载自定义中文数据
train_data = pd.read_csv('train.csv', sep='\t', header=None)
train_data.head()
0 | 1 | |
---|---|---|
0 | 还有双鸭山到淮阴的汽车票吗13号的 | Travel-Query |
1 | 从这里怎么回家 | Travel-Query |
2 | 随便播放一首专辑阁楼里的佛里的歌 | Music-Play |
3 | 给看一下墓王之王嘛 | FilmTele-Play |
4 | 我想看挑战两把s686打突变团竞的游戏视频 | Video-Play |
# 构造数据集迭代器
def coustom_data_iter(texts, labels):for x, y in zip(texts, labels):yield x, yx = train_data[0].values[:]
# 多类标签的one-shot展开
y = train_data[1].values[:]
2.构建词典
from gensim.models import Word2Vec
import numpy as np# 训练Word2vec浅层模型
w2v = Word2Vec(vector_size = 100, # 是指特征向量的维度,默认为100min_count = 3) # 可以对字典做截断,词频少于min_count次数的单词会被丢弃掉,默认值为5w2v.build_vocab(x)
w2v.train(x,total_examples=w2v.corpus_count,epochs=20)
(2732785, 3663560)
Word2Vec可以直接训练模型,一步到位。这里分了三步
●第一步构建一个空模型
●第二步使用 build_vocab 方法根据输入的文本数据 x 构建词典。build_vocab 方法会统计输入文本中每个词汇出现的次数,并按照词频从高到低的顺序将词汇加入词典中。
●第三步使用 train 方法对模型进行训练,total_examples 参数指定了训练时使用的文本数量,这里使用的是 w2v.corpus_count 属性,表示输入文本的数量
如果一步到位的话代码为:
w2v = Word2Vec(x, vector_size=100, min_count=3, epochs=20)
# 将文本转化为向量
def average_vec(text):vec = np.zeros(100).reshape((1,100))for word in text:try:vec += w2v.wv[word].reshape((1,100))except KeyError:continuereturn vec# 将词向量保存为Ndarray
x_vec = np.concatenate([average_vec(z) for z in x])# 保存Word2Vec模型及词向量
w2v.save('w2v_model.pkl')
train_iter = coustom_data_iter(x_vec, y)
len(x), len(x_vec)
(12100, 12100)
label_name = list(set(train_data[1].values[:]))
print(label_name)
[‘Travel-Query’, ‘Radio-Listen’, ‘Alarm-Update’, ‘FilmTele-Play’, ‘TVProgram-Play’, ‘HomeAppliance-Control’, ‘Calendar-Query’, ‘Audio-Play’, ‘Video-Play’, ‘Other’, ‘Music-Play’, ‘Weather-Query’]
3.生成数据批次和迭代器
text_pipeline = lambda x: average_vec(x)
label_pipeline = lambda x: label_name.index(x)
text_pipeline("你在干嘛")
array([[ 0.44942591, 0.37034334, 0.82435736, 0.57583929, -2.19971114,
-0.26266199, 1.54612615, 0.86057729, 0.94607782, -0.56024504,
-1.2855403 , -3.96268934, 1.00411272, -0.78717487, 0.11495599,
1.7602468 , 2.57005858, -2.04502518, 4.77852516, -1.15009709,
2.75658896, -0.7439712 , -0.50604325, 0.23402849, -0.85734205,
-0.64015828, -1.63281712, -1.22751366, 2.32347407, -2.94733901,
1.86662954, 1.20093471, -0.22566201, -0.02635491, 1.06643996,
0.17282215, -0.57236505, 3.87719914, -2.36707568, 1.28222315,
0.16626818, 0.52857486, 0.2673108 , 1.32945235, -0.51124085,
0.68514908, 0.87900299, -0.9519761 , -2.69660458, 1.78133809,
-0.16500359, -2.11181024, -1.16635181, 1.22090494, -0.76275884,
-0.01114198, 0.42615444, -1.23754779, 0.07603779, -0.04253516,
1.32692097, -1.66303211, 2.16462026, -0.9799156 , -0.9070952 ,
0.87778991, -1.08169729, 0.92559687, 0.64850095, 0.20967194,
0.26563513, 1.03787032, 2.3587795 , -0.7511736 , 0.74099658,
-0.15902402, -2.69873536, 0.13621271, 1.08319706, -0.18128317,
-1.8476568 , -0.67964274, -2.43600948, 2.98213428, -1.72624808,
-0.87052085, 2.28517788, -1.87188464, -0.26412555, -0.37503278,
1.51758769, -1.25159131, 0.87080194, 0.85611653, 0.85986885,
-0.60930844, -0.11496616, 0.66294981, -2.06530389, 0.11790894]])
label_pipeline("Travel-Query")
0
from torch.utils.data import DataLoaderdef collate_batch(batch):label_list, text_list= [], []for (_text, _label) in batch:# 标签列表label_list.append(label_pipeline(_label))# 文本列表processed_text = torch.tensor(text_pipeline(_text), dtype=torch.float32)text_list.append(processed_text)label_list = torch.tensor(label_list, dtype=torch.int64)text_list = torch.cat(text_list)return text_list.to(device), label_list.to(device)# 数据加载器,调用示例
dataloader = DataLoader(train_iter,batch_size=8,shuffle=False,collate_fn=collate_batch)
二、模型构建
1.搭建模型
from torch import nnclass TextClassificationModel(nn.Module):def __init__(self, num_class):super(TextClassificationModel, self).__init__()self.fc = nn.Linear(100, num_class)def forward(self, text):return self.fc(text)
2.初始化模型
num_class = len(label_name)
vocab_size = 100000
em_size = 12
model = TextClassificationModel(num_class).to(device)
3.定义训练与评估函数
import timedef train(dataloader):model.train() # 切换到训练模式total_acc, train_loss, total_count = 0, 0, 0log_interval = 50start_time = time.time()for idx, (text, label) in enumerate(dataloader):predicted_label = model(text)optimizer.zero_grad() # grad属性归零loss = criterion(predicted_label, label) # 计算网络输出和真实值之间的差距,label为真实值loss.backward() # 反向传播torch.nn.utils.clip_grad_norm_(model.parameters(), 0.1) # 梯度裁剪optimizer.step() # 每一步自东更新# 记录acc与losstotal_acc += (predicted_label.argmax(1) == label).sum().item()train_loss += loss.item()total_count += label.size(0)if idx % log_interval == 0 and idx > 0:elapsed = time.time() - start_timeprint('| epoch {:1d} | {:4d}/{:4d} batches''| train_acc {:4.3f} train_loss {:4.5f}'.format(epoch, idx, len(dataloader),total_acc/total_count, train_loss/total_count))total_acc, train_loss, total_count = 0, 0, 0start_time = time.time()def evaluate(dataloader):model.eval() # 切换为测试模式total_acc, train_loss, total_count = 0, 0, 0with torch.no_grad():for idx, (text,label) in enumerate(dataloader):predicted_label = model(text)loss = criterion(predicted_label, label) # 计算loss值# 记录测试数据total_acc += (predicted_label.argmax(1) == label).sum().item()train_loss += loss.item()total_count += label.size(0)return total_acc/total_count, train_loss/total_count
三、训练模型
1.拆分数据集并运行模型
from torch.utils.data.dataset import random_split
from torchtext.data.functional import to_map_style_dataset# 超参数
EPOCHS = 10
LR = 5
BATCH_SIZE = 64criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=LR)
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, 1.0, gamma=0.1)
total_accu = None# 构建数据集
train_iter = coustom_data_iter(train_data[0].values[:], train_data[1].values[:])
train_dataset = to_map_style_dataset(train_iter)split_train_, split_valid_ = random_split(train_dataset,[int(len(train_dataset)*0.8), int(len(train_dataset)*0.2)])train_dataloader = DataLoader(split_train_, batch_size=BATCH_SIZE,shuffle=True, collate_fn=collate_batch)valid_dataloader = DataLoader(split_valid_, batch_size=BATCH_SIZE,shuffle=True, collate_fn=collate_batch)for epoch in range(1, EPOCHS + 1):epoch_start_time = time.time()train(train_dataloader)val_acc, val_loss = evaluate(valid_dataloader)# 获取当前的学习率lr = optimizer.state_dict()['param_groups'][0]['lr']if total_accu is not None and total_accu > val_acc:scheduler.step()else:total_accu = val_accprint('-' * 69)print('| epoch {:1d} | time: {:4.2f}s | ''valid_acc {:4.3f} valid_loss {:4.3f} | lr {:4.6f}'.format(epoch,time.time() - epoch_start_time,val_acc,val_loss,lr))print('-' * 69)
| epoch 1 | 50/ 152 batches| train_acc 0.737 train_loss 0.02661
| epoch 1 | 100/ 152 batches| train_acc 0.814 train_loss 0.01831
| epoch 1 | 150/ 152 batches| train_acc 0.829 train_loss 0.01839
---------------------------------------------------------------------
| epoch 1 | time: 0.32s | valid_acc 0.803 valid_loss 0.026 | lr 5.000000
---------------------------------------------------------------------
| epoch 2 | 50/ 152 batches| train_acc 0.831 train_loss 0.01848
| epoch 2 | 100/ 152 batches| train_acc 0.852 train_loss 0.01733
| epoch 2 | 150/ 152 batches| train_acc 0.836 train_loss 0.01894
---------------------------------------------------------------------
| epoch 2 | time: 0.26s | valid_acc 0.783 valid_loss 0.029 | lr 5.000000
---------------------------------------------------------------------
| epoch 3 | 50/ 152 batches| train_acc 0.877 train_loss 0.01177
| epoch 3 | 100/ 152 batches| train_acc 0.904 train_loss 0.00813
| epoch 3 | 150/ 152 batches| train_acc 0.897 train_loss 0.00820
---------------------------------------------------------------------
| epoch 3 | time: 0.26s | valid_acc 0.877 valid_loss 0.010 | lr 0.500000
---------------------------------------------------------------------
| epoch 4 | 50/ 152 batches| train_acc 0.896 train_loss 0.00757
| epoch 4 | 100/ 152 batches| train_acc 0.903 train_loss 0.00654
| epoch 4 | 150/ 152 batches| train_acc 0.899 train_loss 0.00722
---------------------------------------------------------------------
| epoch 4 | time: 0.26s | valid_acc 0.888 valid_loss 0.009 | lr 0.500000
---------------------------------------------------------------------
| epoch 5 | 50/ 152 batches| train_acc 0.903 train_loss 0.00619
| epoch 5 | 100/ 152 batches| train_acc 0.897 train_loss 0.00631
| epoch 5 | 150/ 152 batches| train_acc 0.897 train_loss 0.00678
---------------------------------------------------------------------
| epoch 5 | time: 0.27s | valid_acc 0.880 valid_loss 0.008 | lr 0.500000
---------------------------------------------------------------------
| epoch 6 | 50/ 152 batches| train_acc 0.900 train_loss 0.00611
| epoch 6 | 100/ 152 batches| train_acc 0.904 train_loss 0.00543
| epoch 6 | 150/ 152 batches| train_acc 0.912 train_loss 0.00522
---------------------------------------------------------------------
| epoch 6 | time: 0.26s | valid_acc 0.888 valid_loss 0.008 | lr 0.050000
---------------------------------------------------------------------
| epoch 7 | 50/ 152 batches| train_acc 0.903 train_loss 0.00555
| epoch 7 | 100/ 152 batches| train_acc 0.919 train_loss 0.00477
| epoch 7 | 150/ 152 batches| train_acc 0.902 train_loss 0.00590
---------------------------------------------------------------------
| epoch 7 | time: 0.26s | valid_acc 0.888 valid_loss 0.008 | lr 0.005000
---------------------------------------------------------------------
| epoch 8 | 50/ 152 batches| train_acc 0.909 train_loss 0.00523
| epoch 8 | 100/ 152 batches| train_acc 0.906 train_loss 0.00561
| epoch 8 | 150/ 152 batches| train_acc 0.911 train_loss 0.00533
---------------------------------------------------------------------
| epoch 8 | time: 0.27s | valid_acc 0.888 valid_loss 0.008 | lr 0.000500
---------------------------------------------------------------------
| epoch 9 | 50/ 152 batches| train_acc 0.914 train_loss 0.00485
| epoch 9 | 100/ 152 batches| train_acc 0.902 train_loss 0.00578
| epoch 9 | 150/ 152 batches| train_acc 0.910 train_loss 0.00554
---------------------------------------------------------------------
| epoch 9 | time: 0.26s | valid_acc 0.888 valid_loss 0.008 | lr 0.000050
---------------------------------------------------------------------
| epoch 10 | 50/ 152 batches| train_acc 0.907 train_loss 0.00569
| epoch 10 | 100/ 152 batches| train_acc 0.911 train_loss 0.00496
| epoch 10 | 150/ 152 batches| train_acc 0.908 train_loss 0.00548
---------------------------------------------------------------------
| epoch 10 | time: 0.28s | valid_acc 0.888 valid_loss 0.008 | lr 0.000005
---------------------------------------------------------------------
test_acc, test_loss = evaluate(valid_dataloader)
print('模型准确率为:{:5.4f}'.format(test_acc))
模型准确率为:0.8876
def predict(text, text_pipeline):with torch.no_grad():text = torch.tensor(text_pipeline(text), dtype=torch.float32)print(text.shape)output = model(text)return output.argmax(1).item()# ex_text_str = "随便播放一首专辑阁楼里的佛里的歌"
ex_text_str = "还有双鸭山到淮阴的汽车票吗13号的"model = model.to("cpu")print("该文本的类别是:%s" %label_name[predict(ex_text_str, text_pipeline)])
torch.Size([1, 100])
该文本的类别是:Travel-Query
四、总结
本周主要学了使用word2vec实现文本分类,其中主要了解了训练word2vec浅层模型,同时也更加深入地学习了梯度裁剪。
相关文章:
第N8周:使用Word2vec实现文本分类
文章目录 一、数据预处理1.加载数据2.构建词典3.生成数据批次和迭代器 二、模型构建1.搭建模型2.初始化模型3.定义训练与评估函数 三、训练模型1.拆分数据集并运行模型 四、总结 🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者&a…...

100天精通Python(爬虫篇)——第113天:爬虫基础模块之urllib详细教程大全
文章目录 1. urllib概述2. urllib.request模块 1. urllib.request.urlopen()2. urllib.request.urlretrieve()3. urllib.request.Request()4. urllib.request.install_opener()5. urllib.request.build_opener()6. urllib.request.AbstractBasicAuthHandler7. urllib.request.…...

光谱相机与普通相机的区别
一、成像目的 普通相机:主要目的是记录物体的外观形态,生成人眼可见的、直观的二维图像,重点在于还原物体的形状、颜色和纹理等视觉特征,以供人们进行观赏、记录场景或人物等用途。例如,拍摄旅游风景照片、人物肖像等…...
Mysql数据 新增、修改和删除操作时,这些变化如何被转换为Kafka消息?
Mysql数据 新增、修改和删除操作时,这些变化如何被转换为Kafka消息? 为了在FlinkCDC中配置MySQL同步到Kafka,并采用debezium-json数据格式,我们需要了解当执行新增、修改和删除操作时,这些变化如何被转换为Kafka消息。下面我们将详细介绍这些变化情况,并提供具体的数据样…...
《Python 机器视觉:开启智能视觉新时代》
《Python 机器视觉:开启智能视觉新时代》 一、Python 机器视觉的基石(一)关键库的强大力量(二)环境搭建的便捷路径 二、核心功能与奇妙应用(一)图像的奇幻处理(二)目标检…...

uniapp实现为微信小程序扫一扫的功能
引言 随着微信小程序的快速发展,越来越多的开发者开始关注和学习微信小程序的开发。其中,微信小程序的扫一扫功能是非常常用且实用的功能之一。通过扫描二维码,用户可以获取到相关的信息或者实现特定的功能。 正文 在过去,开发者需要使用微信开发者工具以及相关的开发文档…...

【微信小程序】4plus|搜索框-历史搜索 | 我的咖啡店-综合实训
升级版1-清空全部的再次确认 实现功能: 历史搜索记录展示-历史搜索记录展示10条点击跳转-点击历史搜索记录可同步到搜索框并自动搜索全部删除-可一次性全部删除历史搜索记录全部删除-有再次确认操作展示 进行搜索后留下搜索记录 点击垃圾桶图标,显示【清空全部】 点击【清…...
使用FFmpeg进行拉流和推流操作
FFmpeg是一款强大的多媒体处理工具,可以用于视频的录制、转换、推流和拉流等操作。下面将详细介绍如何使用FFmpeg进行拉流和推流操作。 1. FFmpeg推流操作 推流是将本地的音视频流推送到流媒体服务器上,例如主播将本地电脑上的画面推流到直播平台的流媒…...

Unity微信小游戏接入开放数据域
demo地址:https://github.com/wechat-miniprogram/minigame-unity-webgl-transform/tree/main/Demo/Ranking 官方说明: https://github.com/wechat-miniprogram/minigame-unity-webgl-transform/blob/main/Design/OpenData.md 准备一个Canvas,…...

Spring Boot的开发工具(DevTools)模块中的热更新特性导致的问题
问题: java.lang.ClassCastException: class cn.best.scholarflow.framework.system.domain.entity.SysUser cannot be cast to class cn.best.scholarflow.framework.system.domain.entity.SysUser (cn.best.scholarflow.framework.system.domain.…...

Elasticsearch安装和数据迁移
Elasticsearch安装和数据迁移 Elasticsearch安装 下载并解压Elasticsearch 首先下载Elasticsearch的tar.gz文件,并将其解压: wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.8.2-linux-x86_64.tar.gz tar -xzf elastics…...
Numpy指南:解锁Python多维数组与矩阵运算(下)
文章一览 前言一、排序1.1 numpy.sort1.2 numpy.argsort1.3 numpy.lexsort 二、数组操作2.1 数组元素迭代2.2 数值舍入计算2.3数值取整2.4 数组去重2.5 数组拼接2.6 数组行列交换 三、文件读写3.1 np.fromfile() 读文件3.2 np.loadtxt() 读文件3.3 用 csv 模块逐行处理 CSV 格式…...

路由器刷机TP-Link tp-link-WDR5660 路由器升级宽带速度
何在路由器上设置代理服务器? 如何在路由器上设置代理服务器? 让所有连接到该路由器的设备都能够享受代理服务器的好处是一个不错的选择,特别是当需要访问特定的网站或加速网络连接的时候。下面是一些您可以跟随的步骤,使用路由器…...
VB.NET在 Excel 二次开发中的全面应用
摘要: 本文详细阐述了如何运用VB.NET进行 Excel 的二次开发。首先介绍了开发环境的搭建,包括安装 Visual Studio 及引用 Excel 对象库。接着深入探讨了各种基础操作,如创建 Excel 应用程序对象、打开与操作工作簿、处理工作表与单元格数据等。…...

uni-app使用组件button遇到的问题
在HBuilder X工具中新建一个空白项目, 1、新建一个about页 然后在pages.json文件里加上路由 2、然后看下导航的方法,发现找不到navigateTo方法 参考:button | uni-app官网 第3行和第4行的代码倒是没问题的,第5行的代码有问题执行…...
如何在Express.js中处理异常情况?
在 Express.js 中处理异常情况是确保应用程序稳定性和安全性的重要方面。未处理的错误可能会导致应用崩溃或暴露敏感信息给用户。以下是几种常见的处理异常的方法: 1. 使用 try...catch 和 async/await 对于异步操作,如数据库查询、文件系统访问等&…...

CKA认证 | Day7 K8s存储
第七章 Kubernetes存储 1、数据卷与数据持久卷 为什么需要数据卷? 容器中的文件在磁盘上是临时存放的,这给容器中运行比较重要的应用程序带来一些问题。 问题1:当容器升级或者崩溃时,kubelet会重建容器,容器内文件会…...

ArcGIS Pro地形图四至角图经纬度标注与格网标注
今天来看看ArcGIS Pro 如何在地形图上设置四至角点的经纬度。方里网标注。如下图的地形图左下角经纬度标注。 如下图方里网的标注 如下为本期要介绍的例图,如下: 图片可点击放大 接下来我们来介绍一下 推荐学习:GIS入门模型构建器Arcpy批量…...
策略模式以及优化
使用场景 在一个条件语句中又包含了多个条件语句 具体策略类会过多 把抽象策略和具体策略放在一个枚举类里。 方法 exe() 相当于抽象策略,而A和B就相当于实现了抽象策略的具体策略 这样就只需要一个枚举类就可以解决具体策略类过多的问题 public enum Strategy {A{O…...

linux自动化一键批量检查主机端口
1、准备 我们可以使用下面命令关闭一个端口 sudo iptables -A INPUT -p tcp --dport 端口号 -j DROP我关闭的是22端口,各位可以关其它的或者打开其它端口测试,谨慎关闭22端口!不然就会像我下面一样握手超时😭😭&…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...

select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...

使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...

Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...

ubuntu22.04有线网络无法连接,图标也没了
今天突然无法有线网络无法连接任何设备,并且图标都没了 错误案例 往上一顿搜索,试了很多博客都不行,比如 Ubuntu22.04右上角网络图标消失 最后解决的办法 下载网卡驱动,重新安装 操作步骤 查看自己网卡的型号 lspci | gre…...
基于鸿蒙(HarmonyOS5)的打车小程序
1. 开发环境准备 安装DevEco Studio (鸿蒙官方IDE)配置HarmonyOS SDK申请开发者账号和必要的API密钥 2. 项目结构设计 ├── entry │ ├── src │ │ ├── main │ │ │ ├── ets │ │ │ │ ├── pages │ │ │ │ │ ├── H…...

Tauri2学习笔记
教程地址:https://www.bilibili.com/video/BV1Ca411N7mF?spm_id_from333.788.player.switch&vd_source707ec8983cc32e6e065d5496a7f79ee6 官方指引:https://tauri.app/zh-cn/start/ 目前Tauri2的教程视频不多,我按照Tauri1的教程来学习&…...

【Java多线程从青铜到王者】单例设计模式(八)
wait和sleep的区别 我们的wait也是提供了一个还有超时时间的版本,sleep也是可以指定时间的,也就是说时间一到就会解除阻塞,继续执行 wait和sleep都能被提前唤醒(虽然时间还没有到也可以提前唤醒),wait能被notify提前唤醒…...