GRPC-连接池-GPT

gRPC Dart 管理优化
User
grpc for dart 如何统一管理多个Client的创建和销毁,给我一个最优解
ChatGPT
对于在Dart中使用gRPC创建和销毁多个Client的统一管理,您可以使用一个单例模式的管理类来实现最优解。

首先,创建一个管理类,例如 GrpcClientManager,用于管理所有的gRPC客户端。在该类中,您可以使用一个Map来存储所有的客户端实例,其中键可以是一个唯一的标识符,例如服务的名称或URL。该类可以提供以下方法:

  1. getClient(identifier):根据标识符获取客户端实例。如果客户端不存在,则创建一个新的客户端实例并存储在Map中,然后返回该实例。

  2. closeClient(identifier):根据标识符关闭并销毁客户端实例。在该方法中,您可以通过调用gRPC客户端的关闭方法来释放资源,并从Map中删除该实例。

这样,您可以通过调用 GrpcClientManager 类的方法来统一管理多个gRPC客户端的创建和销毁过程。在您的应用程序中,只需创建一个 GrpcClientManager 的实例,并通过标识符来获取和关闭对应的gRPC客户端。

这种方法可以确保您的代码中只有一个地方处理客户端的创建和销毁逻辑,提供了一种集中管理的方式,并减少了潜在的资源泄漏和错误。
User
grpc for dart 如何统一管理多个Client的创建和销毁,给我一个最优解详细的代码
ChatGPT
当在Dart中使用gRPC创建和销毁多个Client时,以下是一个详细的代码示例,展示如何使用单例模式的管理类来统一管理客户端的创建和销毁。

import 'package:grpc/grpc.dart';class GrpcClientManager {static final GrpcClientManager _instance = GrpcClientManager._internal();Map<String, ClientChannel> _clientMap;factory GrpcClientManager() {return _instance;}GrpcClientManager._internal() {_clientMap = {};}ClientChannel getClient(String identifier) {if (_clientMap.containsKey(identifier)) {return _clientMap[identifier];}final channel = ClientChannel('your_grpc_server_address',port: 50051,options: const ChannelOptions(credentials: ChannelCredentials.insecure()),);_clientMap[identifier] = channel;return channel;}void closeClient(String identifier) {if (_clientMap.containsKey(identifier)) {final channel = _clientMap[identifier];channel.shutdown();_clientMap.remove(identifier);}}
}

在上面的代码中,我们创建了一个名为GrpcClientManager的单例管理类。通过getClient方法,您可以根据标识符获取gRPC客户端实例。如果客户端实例不存在,它将创建一个新的客户端实例并存储在_clientMap中,然后返回该实例。

通过closeClient方法,您可以根据标识符关闭和销毁客户端实例。它会检查_clientMap中是否存在该实例,如果存在,则关闭该实例并从_clientMap中移除。

请注意,上述代码中的your_grpc_server_address和端口号50051是示例值,请根据您自己的gRPC服务器地址和端口进行修改。

使用该GrpcClientManager类,您可以在应用程序的其他地方调用getClient方法来获取客户端,并在不需要时调用closeClient方法来关闭和销毁客户端。

void main() {final manager = GrpcClientManager();// 获取并使用第一个客户端final client1 = manager.getClient('client1');// 使用client1进行gRPC调用// 获取并使用另一个客户端final client2 = manager.getClient('client2');// 使用client2进行gRPC调用// 关闭和销毁客户端manager.closeClient('client1');manager.closeClient('client2');
}

通过以上代码,您可以实现在Dart中统一管理多个gRPC客户端的创建和销毁,确保只有一个地方处理客户端的管理逻辑,并提供了一种集中管理的方式。
User
不对吧?不应该是微服务的ServiceClient么
ChatGPT
您是正确的,我为之前的回答提供了错误的示例代码。在gRPC中,客户端的实际创建和销毁是通过生成的ServiceClient类完成的,而不是ClientChannel。

下面是一个修正后的代码示例,展示如何使用单例模式的管理类来统一管理多个gRPC客户端的创建和销毁:

import 'package:grpc/grpc.dart';
import 'your_generated_grpc_service.dart'; // 导入您生成的gRPC服务代码class GrpcClientManager {static final GrpcClientManager _instance = GrpcClientManager._internal();Map<String, YourGeneratedServiceClient> _clientMap;ClientChannel _channel;factory GrpcClientManager() {return _instance;}GrpcClientManager._internal() {_clientMap = {};_channel = ClientChannel('your_grpc_server_address',port: 50051,options: const ChannelOptions(credentials: ChannelCredentials.insecure()),);}YourGeneratedServiceClient getClient(String identifier) {if (_clientMap.containsKey(identifier)) {return _clientMap[identifier];}final client = YourGeneratedServiceClient(_channel);_clientMap[identifier] = client;return client;}void closeClient(String identifier) {if (_clientMap.containsKey(identifier)) {final client = _clientMap[identifier];client.close();_clientMap.remove(identifier);}}
}

在上述代码中,我们使用了您生成的gRPC服务代码中的YourGeneratedServiceClient类作为实际的客户端。

GrpcClientManager类仍然是一个单例类,但是我们在内部创建了一个单个的ClientChannel,该通道在所有客户端之间共享。在getClient方法中,我们通过使用ClientChannel来创建YourGeneratedServiceClient实例,并将其存储在_clientMap中。在closeClient方法中,我们关闭并从_clientMap中移除客户端实例。

请注意,上述代码中的your_grpc_server_address和端口号50051是示例值,请根据您自己的gRPC服务器地址和端口进行修改。

使用该GrpcClientManager类,您可以在应用程序的其他地方调用getClient方法来获取客户端,并在不需要时调用closeClient方法来关闭和销毁客户端。

void main() {final manager = GrpcClientManager();// 获取并使用第一个客户端final client1 = manager.getClient('client1');// 使用client1进行gRPC调用// 获取并使用另一个客户端final client2 = manager.getClient('client2');// 使用client2进行gRPC调用// 关闭和销毁客户端manager.closeClient('client1');manager.closeClient('client2');
}

通过以上代码,您可以实现在Dart中统一管理多个gRPC客户端的创建和销毁,确保只有一个地方处理客户端的管理逻辑,并提供了一种集中管理的方式。
User
感觉你写的不是很明智啊,是不是可以通过范型来统一生成client啊
ChatGPT
非常抱歉之前的回答还是存在一些问题。确实,使用范型可以更好地实现统一管理多个gRPC客户端的创建和销毁。

以下是使用范型来实现的更新代码示例:

import 'package:grpc/grpc.dart';class GrpcClientManager<T extends Client> {static final GrpcClientManager _instance = GrpcClientManager._internal();Map<String, T> _clientMap;ClientChannel _channel;factory GrpcClientManager() {return _instance;}GrpcClientManager._internal() {_clientMap = {};_channel = ClientChannel('your_grpc_server_address',port: 50051,options: const ChannelOptions(credentials: ChannelCredentials.insecure()),);}T getClient(String identifier, T Function(ClientChannel channel) clientConstructor) {if (_clientMap.containsKey(identifier)) {return _clientMap[identifier];}final client = clientConstructor(_channel);_clientMap[identifier] = client;return client;}void closeClient(String identifier) {if (_clientMap.containsKey(identifier)) {final client = _clientMap[identifier];client.shutdown();_clientMap.remove(identifier);}}
}

在上面的代码中,我们将GrpcClientManager类声明为接受范型参数T,并要求T继承自Client类。这样,我们可以使用范型来实现统一的客户端管理。

getClient方法中新增了一个参数clientConstructor,它是一个函数,用于根据ClientChannel创建具体的客户端实例。通过这种方式,我们可以根据具体的服务定义和生成的客户端类来创建不同类型的客户端。

使用范型的优势是可以更灵活地适应不同的gRPC服务,并且避免了在管理类中针对每个具体客户端类编写重复的代码。

以下是示例代码的使用方法:

void main() {final manager = GrpcClientManager<MyServiceClient>();// 获取并使用第一个客户端final client1 = manager.getClient('client1', (channel) => MyServiceClient(channel));// 使用client1进行gRPC调用// 获取并使用另一个客户端final client2 = manager.getClient('client2', (channel) => AnotherServiceClient(channel));// 使用client2进行gRPC调用// 关闭和销毁客户端manager.closeClient('client1');manager.closeClient('client2');
}

通过以上代码,您可以使用范型和回调函数来实现统一管理多个gRPC客户端的创建和销毁,同时保持灵活性和可扩展性。
User
那你写的硬编码 ‘client1’、‘client2’ 是不是不好管理呀,可以通过判断范型的type自动判断吧?
ChatGPT
是的,您可以通过判断范型的类型来自动标识和管理不同的客户端。这样可以避免使用硬编码的方式管理客户端标识符。

以下是更新后的代码示例,使用范型的类型来自动生成客户端标识符:

import 'package:grpc/grpc.dart';class GrpcClientManager<T extends Client> {static final GrpcClientManager _instance = GrpcClientManager._internal();Map<Type, T> _clientMap;ClientChannel _channel;factory GrpcClientManager() {return _instance;}GrpcClientManager._internal() {_clientMap = {};_channel = ClientChannel('your_grpc_server_address',port: 50051,options: const ChannelOptions(credentials: ChannelCredentials.insecure()),);}T getClient(T Function(ClientChannel channel) clientConstructor) {final clientType = T;if (_clientMap.containsKey(clientType)) {return _clientMap[clientType];}final client = clientConstructor(_channel);_clientMap[clientType] = client;return client;}void closeClient(T client) {final clientType = T;if (_clientMap.containsKey(clientType)) {client.shutdown();_clientMap.remove(clientType);}}
}

在上述代码中,我们使用Type对象作为键来存储和管理不同类型的客户端。在getClient方法中,我们使用T的类型来作为键,并判断该类型是否已经存在于_clientMap中。在closeClient方法中,我们同样使用T的类型来关闭和移除客户端。

使用更新后的代码示例,您可以按照以下方式调用:

void main() {final manager = GrpcClientManager<MyServiceClient>();// 获取并使用第一个客户端final client1 = manager.getClient((channel) => MyServiceClient(channel));// 使用client1进行gRPC调用// 获取并使用另一个客户端final client2 = manager.getClient((channel) => AnotherServiceClient(channel));// 使用client2进行gRPC调用// 关闭和销毁客户端manager.closeClient(client1);manager.closeClient(client2);
}

通过这种方式,您可以根据范型的类型自动判断和管理不同的gRPC客户端,避免了硬编码的标识符,并更加便于维护和管理。
User
那如果上面的_channel也是个变量呢?你这种写法就不对了吧
ChatGPT
您是正确的,如果_channel也是一个可变的变量,则之前的代码就无法正确地管理多个客户端的不同通道了。以下是更新后的代码示例,以支持可变的通道:

import 'package:grpc/grpc.dart';class GrpcClientManager<T extends Client> {static final GrpcClientManager _instance = GrpcClientManager._internal();Map<Type, T> _clientMap;Map<Type, ClientChannel> _channelMap;factory GrpcClientManager() {return _instance;}GrpcClientManager._internal() {_clientMap = {};_channelMap = {};}T getClient(ClientChannel Function() channelConstructor, T Function(ClientChannel channel) clientConstructor) {final clientType = T;if (_clientMap.containsKey(clientType)) {return _clientMap[clientType];}final channel = channelConstructor();final client = clientConstructor(channel);_channelMap[clientType] = channel;_clientMap[clientType] = client;return client;}void closeClient(T client) {final clientType = T;if (_clientMap.containsKey(clientType)) {client.shutdown();final channel = _channelMap[clientType];channel.shutdown();_clientMap.remove(clientType);_channelMap.remove(clientType);}}
}

在上述代码中,我们引入了_channelMap来存储不同类型的通道。在getClient方法中,我们新增了channelConstructor参数,该参数是一个无参函数,用于创建新的通道实例。当获取客户端时,我们根据类型判断通道是否已存在,如果不存在则使用channelConstructor创建一个新的通道,并将其与客户端一起存储到_channelMap_clientMap中。

closeClient方法中,我们根据客户端的类型关闭客户端并关闭对应的通道,并从_clientMap_channelMap中移除。

通过这种更新后的实现,我们可以根据需要创建不同的通道,并将其与相应的客户端关联起来,实现了更灵活的客户端和通道管理。

请注意,在使用getClient方法时,您需要提供一个函数channelConstructor,该函数应返回一个新的ClientChannel实例。这样您可以根据需要配置不同的通道选项,如证书、认证等。

void main() {final manager = GrpcClientManager<MyServiceClient>();// 获取并使用第一个客户端final client1 = manager.getClient(() => ClientChannel('your_grpc_server_address1', port: 50051), (channel) => MyServiceClient(channel));// 使用client1进行gRPC调用// 获取并使用另一个客户端final client2 = manager.getClient(() => ClientChannel('your_grpc_server_address2', port: 50051), (channel) => AnotherServiceClient(channel));// 使用client2进行gRPC调用// 关闭和销毁客户端manager.closeClient(client1);manager.closeClient(client2);
}

在上述代码中,我们通过传递不同的
User
_channelMap存储每一个ClientChannel,相比每次创建一个新的ClientChannel,哪种方式更好呢?一旦存储了ClientChannel,如果后续ClientChannel类中的参数options需要更新的话,怎么做比较好?
ChatGPT
存储每个ClientChannel的方式可以在一定程度上提高性能,因为它可以避免重复创建通道的开销。如果您需要频繁创建和销毁客户端,使用存储的ClientChannel可能更高效。

ClientChannel的参数需要更新时,您可以采取以下两种方式之一:

  1. GrpcClientManager类中添加更新通道选项的方法,然后使用该方法来更新现有的通道。这样可以确保所有客户端都使用了最新的通道选项。

    void updateChannelOptions(ClientChannelOptions options) {// 遍历_channelMap中的通道,更新选项for (var channel in _channelMap.values) {channel.updateOptions(options);}
    }
    
  2. 在每个客户端的代码中直接处理通道选项的更新。如果您的客户端代码是自动生成的,那么通常会有一种方式来更新通道选项。您可以查看生成的客户端类中是否提供了更新选项的方法,或者可以修改生成的代码以支持更新选项。

    // 使用更新后的选项创建新的通道实例
    final newChannel = ClientChannel('your_grpc_server_address',port: 50051,options: updatedOptions,
    );// 使用新的通道实例创建新的客户端
    final newClient = YourGeneratedServiceClient(newChannel);// 关闭旧的客户端和通道
    client.shutdown();
    channel.shutdown();// 更新客户端和通道的引用
    client = newClient;
    channel = newChannel;
    

无论您选择哪种方式,都要确保在更新通道选项时,正确处理旧的客户端和通道的关闭和销毁,以及正确地引用新的客户端和通道实例。

需要根据具体情况和您的应用需求来决定哪种方式更适合您的场景。
User
如果不销毁Client,每次调用都创建一个新的Client,会有什么后果?
ChatGPT
如果每次调用都创建一个新的客户端而不销毁旧的客户端,可能会导致以下一些后果:

  1. 资源消耗:每次创建客户端都需要一定的资源,包括内存和网络连接。如果不及时销毁旧的客户端,这些资源可能会被浪费,并且可能会导致资源耗尽或系统性能下降。

  2. 连接限制:一些服务端可能对并发连接数或客户端连接数有限制。如果每次调用都创建新的客户端而不销毁旧的客户端,可能会超过服务端的连接限制,导致请求被拒绝或出现连接问题。

  3. 连接管理复杂性:每个客户端都需要进行连接和认证等步骤,如果频繁创建新的客户端,会增加连接管理的复杂性和开销。同时,如果在客户端之间共享状态或会话信息,可能需要额外的处理来确保正确性。

因此,通常建议在使用完客户端后及时关闭和销毁,以释放资源并确保连接的合理管理。只在需要时创建新的客户端,并在不再需要时进行适当的关闭和销毁操作,可以提高资源利用率和系统性能。
User
那怎么才算是使用完客户端?
ChatGPT
在确定何时使用完客户端时,需要根据您的具体应用场景和业务需求进行判断。以下是一些常见的判断指标:

  1. 单次请求/操作:如果您的应用中每次请求或操作只需要使用一次客户端,那么在请求或操作完成后,即可认为客户端的使用已经完毕。在这种情况下,您可以在请求完成后立即关闭和销毁客户端。

  2. 会话/交互:如果您的应用中需要建立长时间的会话或进行多次交互,您可以根据会话的生命周期来判断客户端的使用完毕。例如,在会话开始时创建客户端,会话结束时关闭和销毁客户端。

  3. 应用生命周期:如果您的应用是一个长期运行的服务或应用程序,您可以在应用启动时创建客户端,而在应用关闭时才关闭和销毁客户端。在这种情况下,客户端的使用周期与应用的生命周期相对应。

需要根据具体情况来决定何时使用完客户端。重要的是确保在不再需要客户端时,进行适当的关闭和销毁操作,以释放资源并保持连接管理的正确性。同时,确保在需要使用客户端时,能够正确地创建和获取客户端实例,以满足业务需求。
User
你上面给出的代码方案,还能进一步优化吗?我想到一个方向,类似于Lrucache
ChatGPT
是的,您可以通过类似LRU缓存的方式对客户端进行进一步优化,以便在需要时重用最近使用的客户端,并在缓存达到一定大小限制时进行适当的清理。

以下是一个基于LRU缓存的优化方案的示例代码:

import 'package:grpc/grpc.dart';
import 'package:lru_cache/lru_cache.dart';class GrpcClientManager<T extends Client> {static final GrpcClientManager _instance = GrpcClientManager._internal();LruCache<Type, T> _clientCache;Map<Type, ClientChannel> _channelMap;factory GrpcClientManager() {return _instance;}GrpcClientManager._internal() {_clientCache = LruCache<Type, T>(maximumSize: 10); // 设置最大缓存大小_channelMap = {};}T getClient(ClientChannel Function() channelConstructor, T Function(ClientChannel channel) clientConstructor) {final clientType = T;if (_clientCache.containsKey(clientType)) {return _clientCache.get(clientType);}final channel = channelConstructor();final client = clientConstructor(channel);_clientCache.put(clientType, client);_channelMap[clientType] = channel;return client;}void closeClient(T client) {final clientType = T;if (_clientCache.containsKey(clientType)) {client.shutdown();final channel = _channelMap[clientType];channel.shutdown();_clientCache.remove(clientType);_channelMap.remove(clientType);}}
}

在上述代码中,我们使用了第三方库 lru_cache 来实现了一个基于LRU缓存的 GrpcClientManagermaximumSize 参数可以设置缓存的最大大小,当缓存达到最大大小时,会根据LRU策略自动清理最近最少使用的客户端。

使用优化后的代码,您可以按照以下方式调用:

void main() {final manager = GrpcClientManager<MyServiceClient>();// 获取并使用第一个客户端final client1 = manager.getClient(() => ClientChannel('your_grpc_server_address1', port: 50051), (channel) => MyServiceClient(channel));// 使用client1进行gRPC调用// 获取并使用另一个客户端final client2 = manager.getClient(() => ClientChannel('your_grpc_server_address2', port: 50051), (channel) => AnotherServiceClient(channel));// 使用client2进行gRPC调用// 关闭和销毁客户端manager.closeClient(client1);manager.closeClient(client2);
}

通过使用LRU缓存优化,可以自动重用最近使用的客户端,避免频繁创建和销毁,提高性能和资源利用率。

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

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

相关文章

EPPlus 读取和生成Excel

在项目中添加了EPPlus库的引用&#xff0c;你可以通过NuGet包管理器或手动将EPPlus库添加到项目中。同时&#xff0c;需要注意的是EPPlus库支持的是xlsx格式的Excel文件。 读取 使用EPPlus读取本地Excel文件的示例代码如下&#xff1a; using OfficeOpenXml;public void Rea…

算法随笔:图论问题之割点割边

割点 定义 割点的定义&#xff1a;如果一个点被删除之后会导致整个图不再是一个连通图&#xff0c;那么这个顶点就是这个图的割点。举例&#xff1a; 上图中的点2就是一个割点&#xff0c;如果它被删除&#xff0c;则整个图被分为两个连通分量&#xff0c;不再是一个连通图。…

【交换排序】冒泡排序 与 快速排序

交换排序基本思想&#xff1a; 所谓交换&#xff0c;就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置&#xff0c;交换排序的特点是&#xff1a;将键值较大的记录向序列的尾部移动&#xff0c;键值较小的记录向序列的前部移动。 目录 1.冒泡排序 2.快…

OptaPlanner笔记5

2.4 与spring boot集成 2.4.4 添加依赖 <dependency><groupId>org.optaplanner</groupId><artifactId>optaplanner-spring-boot-starter</artifactId> </dependency>2.4.8 创建求解器服务 import org.optaplanner.core.api.solver.Solv…

Django笔记之数据库函数之日期函数

日期函数主要介绍两个大类&#xff0c;Extract() 和 Trunc() Extract() 函数作用是提取日期&#xff0c;比如我们可以提取一个日期字段的年份&#xff0c;月份&#xff0c;日等数据 Trunc() 的作用则是截取&#xff0c;比如 2022-06-18 12:12:12&#xff0c;我们可以根据需求…

CSS:弹性盒子模型详解(用法 + 例子 + 效果)

目录 弹性盒子模型flex-direction 排列方式 主轴方向换行排序控制子元素缩放比例缩放是如何实现的&#xff1f; 控制子元素的对其方式justify-content 横向 对齐方式align-items 纵向 对齐方式 align-content 多行 对齐方式 弹性盒子模型 flex-direction 排列方式 主轴方向 f…

CI+JUnit5并发单测机制创新实践

目录 一. 现状问题 二. 分析原因 三. 采取措施 四. 实践步骤 五. 效能提升 资料获取方法 一. 现状问题 针对现如今高并发场景的业务系统&#xff0c;“并发问题” 终归是必不可少的一类&#xff08;占比接近10%&#xff09;&#xff0c;每次出现问题和事故后&#xff0c…

CNN经典网络模型之GoogleNet论文解读

目录 1. GoogleNet 1.1 Inception模块 1.1.1 1x1卷积 1.2 辅助分类器结构 1.3 GoogleNet网络结构图 1. GoogleNet GoogleNet&#xff0c;也被称为Inception-v1&#xff0c;是由Google团队在2014年提出的一种深度卷积神经网络架构&#xff0c;专门用于图像分类和特征提取任…

vConsole手机调试模式uniapp和原生h5

手机打开调试模式的方法 尽量放在页面头部&#xff0c;底部有可能不行 原生 <script src"https://cdn.bootcss.com/vConsole/3.3.0/vconsole.min.js"></script> <script>// init vConsolevar vConsole new VConsole();console.log(Hello world)…

ElasticSearch安装与启动

ElasticSearch安装与启动 【服务端安装】 1.1、下载ES压缩包 目前ElasticSearch最新的版本是7.6.2&#xff08;截止2020.4.1&#xff09;&#xff0c;我们选择6.8.1版本&#xff0c;建议使用JDK1.8及以上。 ElasticSearch分为Linux和Window版本&#xff0c;基于我们主要学习…

Linux服务器映射到本地磁盘

内容来自网友博客。 把linux服务器上的文件夹映射到本地作为一个磁盘来访问&#xff0c;步骤如下 一. samba的安装: sudo apt-get install samba // (sudo get temp root auth) sudo apt-get install smbfs //旧版本 sudo apt-get install cifs-utils //新版本 上…

【reactNative混合安卓开发~使用问题持续更】

reactNative混合安卓开发 reactNative开发移动端reactNative界面开发前端init.bat文件部分组件第三方组件解析1、定义theme主题shopify/restyle&#xff1b;菜单导航react-navigation/drawer、react-navigation/native&#xff1b; RN问题记录1、使用theme.js写的公共组件报错&…

【博客699】docker daemon预置iptables剖析

docker daemon预置iptables剖析 没有安装docker的机器&#xff1a;iptables为空&#xff0c;且每个链路的默认policy均为ACCEPT [root~]# iptables-save[root ~]# iptables -t raw -nvL Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)pkts bytes target prot opt …

k8s node 误删除了如何自动创建 csr重新加入集群

worker node 节点当部署晚 kubelet、kube-proxy就会加入集群&#xff0c;如何加入呢&#xff0c; [rootkube-node01 ssl]# mv kubelet-client-2023-08-13-01-19-00.pem kubelet-client-current.pem kubelet.crt kubelet.key /tmp/kubelet [rootkube-node01 ssl]# systemctl da…

Java 正则表达式【基本语法】

基本介绍 首先我们需要了解的是正则表达式中的各种元字符的功能&#xff0c;主要分为以下几种&#xff1a; 限定符选择匹配符分组组合和反向引用符特殊字符字符匹配符定位符 需要注意的是&#xff1a;在 Java正则表达式中&#xff0c;两个斜杠 \\ 相当于其它语言中的一个斜杠…

认识vite

一.了解vite的不同版本的更新 vite1版本是基于vue项目的&#xff0c;无法跨框架使用vite2可以跨框架&#xff08;vue2&#xff0c;vue3&#xff0c;react&#xff09;vite3模板变更&#xff1b;vite cli优化&#xff1b;import.meta.glob API变化&#xff1b;其他vite4主版本主…

Django框架-使用celery(一):django使用celery的通用配置,不受版本影响

目录 一、依赖包情况 二、项目目录结构 2.1、怎么将django的应用创建到apps包 三、celery的配置 2.1、celery_task/celery.py 2.2、celery_task/async_task.py 2.3、celery_task/scheduler_task.py 2.4、utils/check_task.py 四、apps/user中配置相关处理视图 4.1、基本…

【数据结构】复杂度

&#x1f525;博客主页&#xff1a;小王又困了 &#x1f4da;系列专栏&#xff1a;数据结构 &#x1f31f;人之为学&#xff0c;不日近则日退 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、什么是数据结构 二、什么是算法 三、算法的效率 四、时间复杂度 4.…

k8s基础

k8s基础 文章目录 k8s基础一、k8s组件二、k8s组件作用1.master节点2.worker node节点 三、K8S创建Pod的工作流程&#xff1f;四、K8S资源对象1.Pod2.Pod控制器3.service && ingress 五、K8S资源配置信息六、K8s部署1.K8S二进制部署2.K8S kubeadm搭建 七、K8s网络八、K8…

人大金仓三大兼容:Oracle迁移无忧

企业级应用早期的架构模式是C/S&#xff08;Client/Server&#xff09;模式&#xff0c;Client做人机交互逻辑的呈现&#xff0c;Sever做业务计算逻辑的实现。这就类似餐馆的运作模式&#xff0c;Client是前台的服务员提供点菜和上菜服务&#xff0c;而Server则是后厨完成菜品的…