并行执行的概念—— 《OceanBase 并行执行》系列 一

From 产品经理:
这是一份姗姗来迟的关于OceanBase并行执行的系统化产品文档。
自2019年起,并行执行功能已被许多客户应用于多种场景之中,其重要性日益凸显。然而,遗憾的是,我们始终未能提供一份详尽的用户使用文档,这无疑给业务团队在运用并行执行功能时带来了诸多困扰。今日,我们决心弥补这一缺憾。
关于并行执行的内容,我们将通过七篇博客系列进行详尽的解析,而本文正是这一系列的第一篇。

并行执行是指单个SQL语句能够同时利用多个 CPU 和 I/O 资源的能力。本文将深入探讨并行执行的工作机制,同时阐明如何在OceanBase数据库中对其进行控制、管理与监控。

1 并行执行概念

并行执行是指将一个 SQL 查询任务分成多个子任务,并允许这些子任务在多个处理器上同时运行,以提高整个查询任务的执行效率。在现代计算机系统中,多核处理器、多线程和高速网络连接广泛应用,这使得并行执行成为了一种可行的高效率查询技术。

并行执行能够极大降低计算密集型大查询的响应时间,被广泛应用在离线数据仓库、实时报表、在线大数据分析等业务场景,同时还应用在批量导数,快速构建索引表等领域。

以下场景会从并行执行中获益:

  • 大表扫描,大表连接,大数据量排序,聚合
  • 大表 DDL 操作,如修改主键、改变列类型,建索引等
  • 从已有大数据建表(Create Table As Select)
  • 批量插入、删除、更新

本节包含如下内容:

  • 什么场景适用并行执行
  • 什么场景不适用并行执行
  • 硬件要求
  • 并行执行工作原理
  • 并行执行工作线程
  • 通过均衡负载来优化性能

1.1 什么场景适用并行执行

并行执行通过充分利用多个 CPU 和 IO 资源,以达到降低 SQL 执行时间的目的。

当满足下列条件时,使用并行执行会优于串行执行:

  • 访问的数据量大
  • SQL 并发低
  • 要求低延迟
  • 有充足的硬件资源

并行执行用多个处理器协同并发处理同一任务,在这样的系统中会有收益:

  • 多处理器系统(SMPs)、集群
  • IO 带宽足够
  • 内存富余(可用于处理内存密集型操作,如排序、建 hash 表等)
  • 系统负载不高,或有峰谷特征(如系统负载一般在 30% 以下)

如果你的系统不满足上述特征,那么并行执行可能不会带来显著收益。在一些高负载,小内存,或 IO 能力弱的系统里,并行执行甚至会带来负面效果。

并行执行不仅适用于离线数据仓库、实时报表、在线大数据分析等分析型系统,而且在 OLTP 领域也能发挥作用,可用于加速 DDL 操作、以及数据跑批工作等。但是,对于 OLTP 系统中的普通 SELECT 和 DML 语句,并行执行并不适用。

1.2 什么场景不适用并行执行

串行执行使用单个线程来执行数据库操作,在下面这些场景下使用串行执行优于并行执行:

  • Query 访问的数据量很小
  • 高并发
  • Query 执行时间小于 100 毫秒

并行执行一般不适用于如下场景:

  • 系统中的典型 SQL 执行时间都在毫秒级。并行查询本身有毫秒级的调度开销,对于短查询来说,并行执行带来的收益完全会被调度开销所抵消。
  • 系统负载本就很高。并行执行的设计目标就是去充分利用系统的空余资源,如果系统本身已经没有空余资源,那么并行执行并不能带来额外收益,相反还会影响系统整体性能。

1.3 硬件要求

并行执行对硬件没有特殊要求。需要注意的是,CPU 核数、内存大小、存储 I/O 性能、网络带宽都会影响并行执行性能,其中任意一项成为瓶颈都会拖累并行执行性能。

1.4 并行执行工作原理

并行执行将一个 SQL 查询任务分解成多个子任务,并调度这些子任务到多个处理器上运行。

本节包含如下内容:

  • SQL 语句的并行执行
  • 生产者消费者流水线模型
  • 并行的粒度
  • 生产者和消费者之间的数据分发方式
  • 生产者和消费者之间的数据传输机制

1.4.1 SQL 语句的并行执行

当一个 SQL 被解析为并行执行计划后,会按照下面的步骤执行:

  1. SQL 主线程(接收、解析SQL的线程)根据计划形态预约并行执行需要的线程资源。这些线程资源可能来自集群中的多台机器。
  2. SQL 主线程打开并行调度算子(PX COORDINATOR)。
  3. 并行调度算子解析计划,将它们切分成多个操作步骤,按照自底向上的顺序调度执行这些操作。每个操作都会尽可能并行执行。
  4. 当所有操作并行执行完成后,并行调度算子会接收计算结果,并将结果吐给它的上层算子(如 Aggregate 算子),串行完成剩余不可并行的计算(如最终的 SUM 计算)。

1.4.2 生产者-消费者流水线模型

并行执行使用生产者-消费者模型来进行流水执行。并行调度算子解析计划,将它们切分成多个操作步骤,每个操作步骤称之为一个 DFO(Data Flow Operation)

一般情况下,并行调度算子在同一时刻会启动两个 DFO,DFO 之间会以生产者-消费者的模式连接起来,这称为 DFO 间的并行执行。每个 DFO 会使用一组线程来执行,这称为 DFO 内的并行执行,这个 DFO 使用的线程数称为 DOP(Degree Of Parallisim)

上一阶段的消费者 DFO 会成为下一阶段的生产者 DFO。在并行调度算子的协调下,会同时启动消费者 DFO 和生产者 DFO。

下图中:

(1)DFO A 生成的数据会立即传输给DFO B 进行计算;

(2)DFO B 完成计算后,会将数据暂存在当前线程中,等待它的上层 DFO C 启动;

(3)当 DFO B 收到 DFO C 启动完成通知后,会将自己的角色转变成生产者,开始向 DFO C 传输数据,DFO C 收到数据后开始计算。

1705634262

考虑下面的查询:

create table game (round int primary key, team varchar(10), score int)partition by hash(round) partitions 3;insert into game values (1, "CN", 4), (2, "CN", 5), (3, "JP", 3);
insert into game values (4, "CN", 4), (5, "US", 4), (6, "JP", 4);select /*+ parallel(3) */ team, sum(score) total from game group by team;

查询语句对应的执行计划:

OceanBase(admin@test)>explain select /*+ parallel(3) */ team, sum(score) total from game group by team;
+---------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                              |
+---------------------------------------------------------------------------------------------------------+
| =================================================================                                       |
| |ID|OPERATOR                     |NAME    |EST.ROWS|EST.TIME(us)|                                       |
| -----------------------------------------------------------------                                       |
| |0 |PX COORDINATOR               |        |1       |4           |                                       |
| |1 | EXCHANGE OUT DISTR          |:EX10001|1       |4           |                                       |
| |2 |  HASH GROUP BY              |        |1       |4           |                                       |
| |3 |   EXCHANGE IN DISTR         |        |3       |3           |                                       |
| |4 |    EXCHANGE OUT DISTR (HASH)|:EX10000|3       |3           |                                       |
| |5 |     HASH GROUP BY           |        |3       |2           |                                       |
| |6 |      PX BLOCK ITERATOR      |        |1       |2           |                                       |
| |7 |       TABLE SCAN            |game    |1       |2           |                                       |
| =================================================================                                       |
| Outputs & filters:                                                                                      |
| -------------------------------------                                                                   |
|   0 - output([INTERNAL_FUNCTION(game.team, T_FUN_SUM(T_FUN_SUM(game.score)))]), filter(nil), rowset=256 |
|   1 - output([INTERNAL_FUNCTION(game.team, T_FUN_SUM(T_FUN_SUM(game.score)))]), filter(nil), rowset=256 |
|       dop=3                                                                                             |
|   2 - output([game.team], [T_FUN_SUM(T_FUN_SUM(game.score))]), filter(nil), rowset=256                  |
|       group([game.team]), agg_func([T_FUN_SUM(T_FUN_SUM(game.score))])                                  |
|   3 - output([game.team], [T_FUN_SUM(game.score)]), filter(nil), rowset=256                             |
|   4 - output([game.team], [T_FUN_SUM(game.score)]), filter(nil), rowset=256                             |
|       (#keys=1, [game.team]), dop=3                                                                     |
|   5 - output([game.team], [T_FUN_SUM(game.score)]), filter(nil), rowset=256                             |
|       group([game.team]), agg_func([T_FUN_SUM(game.score)])                                             |
|   6 - output([game.team], [game.score]), filter(nil), rowset=256                                        |
|   7 - output([game.team], [game.score]), filter(nil), rowset=256                                        |
|       access([game.team], [game.score]), partitions(p[0-2])                                             |
|       is_index_back=false, is_global_index=false,                                                       |
|       range_key([game.round]), range(MIN ; MAX)always true                                              |
+---------------------------------------------------------------------------------------------------------+
29 rows in set (0.003 sec)

select语句的执行计划会首先对 game 表做全表扫描,按照 team 做分组求和,然后算出每个 team 的总分数。这个查询的执行示意图如下:

1705634280

从图中可以看到,这个查询实际使用了 6 个线程。

  • 第一步:前三个线程负责 game 表扫描,并且在每个线程内对 game.team 数据做预聚合;
  • 第二步:后三个线程负责对预聚合的数据做最终聚合;
  • 第三步:最终聚合结果发给并行调度器,由它返回给客户端。

第一步的数据发给第二步时,需要用 game.team 字段做 hash,决定将预聚合数据发给哪个线程。

1.4.3 并行的粒度

并行数据扫描的基本工作单元称为 granule。OceanBase 将表扫描工作划分成多个 granule,每个 granule 描述了一段扫描任务的范围。因为 granule 不会跨表分区 ,所以每段扫描任务一定是位于一个分区内。

根据 granule 的粒度特征,可以划分为两类:

  • Partition Granule

Partition granule 描述的范围是一整个分区,扫描任务涉及到多少个分区,就会划分出多少个 partition granule。这里的分区既可以是主表分区,也可以是索引分区。

Partition Granule 最常用的应用场景是 partition wise join,两张表里对应的分区通过 partition granule 可以确保被同一个工作线程处理。

  • Block Granule

Block granule 描述的范围是一个分区中的一段连续数据。数据扫描场景里,一般都是使用 block granule 划分数据。每个分区都会被划分为若干个 block,这些 block 再以一定的规则串联起来形成一个任务队列,供并行工作线程消费。

1705634306

在给定并行度的情况下,为了确保扫描任务的均衡,优化器会自动选择将数据划分成分区粒度(Partition Granule)或块粒度(Block Granule)。如果选择了 Block Granule,并行执行框架会在运行时决策 block 的划分,总体原则是确保一个 block 既不会太大,也不会太小。太大,可能导致数据倾斜,让部分线程少干活;太小,会导致频繁的扫描切换开销。

划分好分区粒度后,每个粒度对应一个扫描任务。Table Scan 扫描算子会一个接一个地处理这些扫描任务,处理完一个之后,接着处理下一个,直到所有任务处理完毕。

1.4.4 生产者和消费者之间的数据分发方式

数据分发方式指的是,数据从一组并行执行工作线程(生产者)发送给另一组(消费者)时使用的方法。优化器会使用一系列的优化策略,决策使用哪种数据重分布方式,以达到最优的性能。

并行执行中的常见数据分发方式包括:

  • Hash Distribution

使用 Hash distribution 发送数据时,生产者根据 distribution key 对数据行计算 hash 值并取模,算出发给哪个消费者工作线程。大部分情况下,使用 hash distribution 能将数据较为均匀的分发给多个消费者线程。

  • Pkey Distribution

使用 Pkey Distribution 时,生产者计算出数据行对应的目标表所在分区,然后将行数据发给处理这个分区的消费者线程。

Pkey Distribution 常用于 partitial partitions wise join 场景。在 partitial partitions wise join 场景下,消费者侧的数据不需要做重分布,就可以和生产者侧的数据做 Partition Wise Join。这种方式可以减少网络通信量,提升性能。

  • Pkey Hash Distribution

使用 Pkey Hash Distribution 时,生产者首先需要计算出数据行对应的目标表所在的分区。然后,根据 distribution key 对数据行进行 hash 计算,以便决定将其发给哪一个消费者线程来处理。

Pkey Hash Distribution 常常应用于 Parallel DML 场景中。在这种场景下,一个分区可以被多个线程并发更新,因此需要使用 Pkey Hash Distribution 来确保相同值的数据行被同一个线程处理,不同值的数据行尽可能均分到多个线程处理。

  • Broadcast Distribution

使用 broadcast distribution 时,生产者将每一个数据行发送消费者端的每一个线程,使得消费者端每一个线程都拥有全量的生产者端数据。

Broadcast distribution 常用于将小表数据复制到所有执行 join 的节点,然后做本地 join 操作。这种方式可以减少网络通信量。

  • Broadcast to Host Distribution(简称 BC2HOST)

使用 broadcast to host distribution 时,生产者将每一个数据行发送消费者端的每一个节点上,使得消费者端每一个节点都拥有全量的生产者端数据。然后,节点里的消费者线程协同处理这份数据。

Broadcast to host distribution 常用于 NESTED LOOP JOIN、SHARED HASH JOIN 场景。NESTED LOOP JOIN 场景里,消费端的每个线程会从共享数据里取一部分数据行作为驱动数据,去目标表里做 join 操作;SHARED HASH JOIN 场景里,消费端的每个线程会基于共享数据协同构建 hash 表,避免每个线程独立构建相同 hash 表导致的不必要开销。

  • Range Distribution

使用 Range distribution 时,生产者将数据按照 range 范围做划分,让不同消费者线程处理不同范围的数据。

Range distribution 常用于排序场景,各个消费者线程只需排序好发给自己的数据,数据就能在全局范围内有序。

  • Random Distribution

使用 Random distribution 时,生产者将数据随机打散,发给消费者线程,使得每个消费者线程处理的数据数量几乎一致,从而达到均衡负载的目的。

Random distribution 常用于多线程并行 UNION ALL 场景,该场景只要求数据打散,负载均衡,数据之间无其它关联约束。

  • Hybrid Hash Distribution

Hybrid hash distribtuion 用于自适应的 join 算法。结合收集的统计信息,OceanBase 提供了一组配置项来定义常规值和高频值。Hybrid hash distribtuion 方法将 join 两侧的常规值做 hash 分布,左侧的高频值使用 broadcast 分布,右侧的高频值使用 random 分布。

1705634332

1.4.5 生产者和消费者之间的数据传输机制

并行调度算子在同一时刻会启动两个 DFO,DFO 之间会以生产者-消费者的模式连接起来并行执行。为了方便在生产者和消费者之间传输数据,需要创建一个传输网络。

例如,生产者 DFO 以 DOP = 2 来做数据扫描,消费者 DFO 以 DOP = 3 来做数据聚合计算,每个生产者线程都会创建 3 个虚拟链接去连接消费者线程,总计会创建 6 个虚拟链接。如下图:

1705634356

生产者和消费者之间创建的虚拟传输网络被称为数据传输层(Data Transfer Layer,简称 DTL)。OceanBase 并行执行框架中,所有的控制消息和行数据都通过 DTL 进行收发。每个工作线程可以对外建立数千个虚拟链接,具有高度的可扩展性。除此之外,DTL 还具有数据缓冲、批量数据发送和自动流量控制等能力。

当 DTL 链接的两端位于同一个节点时,DTL 会通过内存拷贝的方式来传递消息;当 DTL 链接的两端位于不同节点时,DTL 会通过网络通信的方式来传递消息。

1.5 并行执行工作线程

一个并行查询会使用两类线程:1个主线程,若干个并行工作线程。其中主线程和普通的 TP 查询使用的线程没有任何区别,来自普通工作线程池,并行工作线程来自专用线程池。

OceanBase 使用专用线程池模型来分配并行工作线程。每个租户在其所属的各个节点里都有一个租户专属的并行执行线程池,并行查询工作线程都通过这个线程池来分配。

并行调度算子在调度每个 DFO 之前,会去线程池中申请线程资源。当 DFO 执行完成时,会立即源释放线程资源。

线程池的初始大小为 0,按需增长,没有上限。为了避免空闲线程数过多,线程池引入自动回收机制。对于任意线程:

  • 如果空闲时间超过 10 分钟,并且线程池中剩余线程数大于 8 个,则被回收销毁;
  • 如果空闲时间超过 60 分钟,则无条件销毁

虽然线程池的大小没有上限,但是通过下面两个机制,能在绝大多数场景里形成事实上限:

  1. 并行执行开始执行前,需要通过 Admission 模块预约线程资源,预约成功后才能投入执行。通过这个机制,能限制并发查询数量。Admission 模块的详细内容参考本文中 《3 并发控制与排队》一节。
  2. 查询每次从线程池申请线程时,单次申请的线程数量不会超过 N, N 等于租户 UNIT 的 MIN_CPU 乘以 px_workers_per_cpu_quota,如果超过,则最多只分配 N 个线程。px_workers_per_cpu_quota 是租户级配置项,默认值为 10。例如,一个 DFO 的 DOP = 100,它需要从 A 节点申请 30 个线程,从 B 节点申请 70 个线程,UNIT 的 MIN_CPU = 4,px_workers_per_cpu_quota = 10,那么 N = 4 * 10 = 40。最终这个 DFO 在 A 节点上实际申请到 30 个线程,B 节点上实际申请到 40 个线程,它的实际 DOP 为 70。

1.6 通过均衡负载来优化性能

为了达到最优性能,所有工作线程分到的工作任务应该尽量相等。

SQL 使用 Block Granule 划分任务的时候,工作任务会动态地分配到工作线程之间。这样可以最小化工作负载不均衡问题,即一些工作线程的工作量不会明显超过其它工作线程。SQL 使用 Partition Granule 划分任务时,可以通过让任务数是工作线程数的整数倍来优化性能。这适用于 Partition Wise Join 和并行 DML 场景。

举个例子,假设一个表有 16 个分区,每个分区的数据量差不多。你可以使用 16 工作线程(DOP 等于 16)以大约十六分之一的时间完成工作,你也可以使用五个工作线程以五分之一的时间完成工作,或使用两个线程以一半的时间完成工作。

但是,如果你使用 15 个线程来处理 16 个分区,则第一个线程完成一个分区的工作后,就开始处理第 16 个分区。而其他线程完成工作后,它们变为空闲状态。当每个分区的数据量差不多时,这种配置会导致性能不优;当每个分区的数据量有所差异时,实际性能则会因情况而异。

类似地,假设你使用 6 个线程来处理 16 个分区,每个分区的数据量差不多。在这种情况下,每个线程在完成其第一个分区后,会处理第二个分区,但只有四个线程会处理第三个分区,而其他两个线程会保持空闲。

一般来说,不能假设在给定数量的分区(N)和给定数量的工作线程(P)上执行并行操作所花费的时间等于 N 除以 P。这个公式没有考虑到一些线程可能需要等待其他线程完成最后的分区。但是,通过选择适当的 DOP,可以最小化工作负载不均衡问题并优化性能。

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

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

相关文章

VMware下Ubuntu的安装教程

文章目录 一、Ubuntu如何下载1.下载官方地址https://ubuntu.com/2.点选Ubuntu服务器版本3.点击下载Ubuntu服务器版本iso镜像二、VMware安装Ubuntu服务器系统1.创建虚拟机2.选择下载好的Ubuntu服务器镜像3.创建安装完成三、Ubuntu Server如何设置1.Ubuntu Server没有中文所以全都…

突破AI迷雾:英特尔携手星环科技打造向量数据库革新方案,直降大模型幻觉

去年爆火的大模型,正在从百模大战走向千行百业落地应用。不过行业数据规模有限,企业数据隐私安全的要求等等因素,都让行业大模型的准确率面临挑战。近期发布的《CSDN AI 开发者生态报告》数据显示,“缺乏数据/数据质量问题”在大模…

Pycharm远程同步的mapping与sync

用Pycharm进行项目远程部署的时候会遇到两个同步文件,一个是点击 tools—>deployment—>configration——>mapping 一个是链接虚拟环境的时候会有一个sync,那么这两种同步有什么区别呢? 区别就是,2包括1,要用…

常见错误以及如何纠正它们

团队和关键结果目标 (OKR) 之间的关系是深刻且至关重要的。总而言之,一切都应该是相互关联的。正如《团队的智慧》一书中所强调的: 在团队中,没有什么比每个成员对共同目标和一组相关绩效目标的承诺更重要的了,而团队对此负有共同…

【热门话题】实用Chrome命令:提升前端开发效率的利器

🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 ​💫个人格言: "如无必要,勿增实体" 文章目录 实用Chrome命令:提升前端开发效率的利器引言目录1. 快速打开Chrome …

Django调用MTP服务器给指定邮箱发送邮件

Django调用MTP服务器发送邮箱 邮箱的激活链接含有用户数据不能直接发送需要对其进行加密 发送邮箱是借助SMTP服务器进行中转 一. 配置SMTP服务中的邮箱信息以及激活链接 1. 配置邮箱权限 打开网易邮箱设置点击POP3 开启选项 注 : 在打开的过程中会弹出授权密码一点要保存 …

C++ 递归函数

一 递归函数 递归函数(Recursive Function)即自调用函数,即在函数体内有直接或间接地自己调用自己的语句。 大多数递归函数都能够用非递归函数代替。 例如:求两个整数a,b的最大公约数。 算法描述: 大多数递归函数都能用非递归…

Angular中组件之间的传值

Angular中组件之间的传值 文章目录 Angular中组件之间的传值前言一、父亲向儿子传值二、儿子向父亲传值三、爷爷向孙子传值四、兄弟之间的传值 前言 Angular的组件是构成应用的基础单元,它们封装了HTML模板、TypeScript代码以及CSS样式,以实现特定的功能…

rag-embeddings基础流程

什么是检索增强的生成模型 LLM 固有的局限性 LLM 的知识不是实时的LLM 可能不知道你私有的领域/业务知识 检索增强生成 RAG(Retrieval Augmented Generation)顾名思义,通过检索的方法来增强生成模型的能力。 类比:你可以把这个…

CTK库编译-01

地址 官网地址:Commontk github地址:https://github.com/commontk/CTK 编译环境 Qt套件: IDE:VS2022 使用vs2022 文件->打开->cmake 修改根目录下的CMakeLists.txt 默认只编译core模块,所以需要把部分模块…

一文读懂Python的`__init__`,`__init__`方法的终极指南

大家好,今天给大家介绍一个Python中一个特殊的函数__init__。 在Python中,__init__方法是一个特殊的函数,它在创建类的新实例时自动调用。它的作用类似于其他编程语言中的构造函数,用于初始化对象的状态。这篇文章将带你深入了解…

资料总结分享:SAM,bam,bed文件格式

目录 sam文件 bam文件 bed 文件 sam文件 SAM(Sequence Alignment/Map)文件是存储测序数据比对结果的一种常见格式。SAM文件通常用于存储DNA或RNA测序数据在参考基因组上的比对结果。 SAM文件由多行文本组成,每一行代表一个比对结果。SAM文…

QX-mini51学习---(2)点亮LED

目录 1什么是ed 2led工作参数 3本节相关原理图分析 4本节相关c 5实践 1什么是ed 半导体发光二极管,将电能转化为光能,耗电低,寿命长,抗震动 长正短负,贴片是绿点处是负极 2led工作参数 3本节相关原理图分析 当…

计算图:深度学习中的链式求导与反向传播引擎

在深度学习的世界中,计算图扮演着至关重要的角色。它不仅是数学计算的图形化表示,更是链式求导与反向传播算法的核心。本文将深入探讨计算图的基本概念、与链式求导的紧密关系及其在反向传播中的应用,旨在为读者提供一个全面而深入的理解。 计…

嵌入式5-7

练习:优化登录框,输入完用户名和密码后,点击登录,判断账户是否为 Admin 密码 为123456,如果判断成功,则输出登录成功,并关闭整个登录界面,如果登录失败,则提示登录失败&a…

JavaScript异步编程——03-Ajax传输json和XML

Ajax 传输 JSON JSON 的语法 JSON(JavaScript Object Notation):是 ECMAScript 的子集。作用是进行数据的交换。语法更为简洁,网络传输、机器解析都更为迅速。 语法规则: 数据在键值对中 数据由逗号分隔 花括号保存对象 方括号保存数组…

远程桌面连接不上,远程桌面连接不上的专业解决策略

在信息技术领域,远程桌面连接是一种非常重要的工具,它允许用户从任何地点、任何时间访问和操作远程计算机。然而,当远程桌面连接出现问题时,可能会严重影响工作效率。以下是一些可能导致远程桌面连接不上的原因以及相应的解决方案…

Verilog刷题笔记47

题目: From a 1000 Hz clock, derive a 1 Hz signal, called OneHertz, that could be used to drive an Enable signal for a set of hour/minute/second counters to create a digital wall clock. Since we want the clock to count once per second, the OneHer…

普洱茶泡多少茶叶才算淡茶?

普洱茶淡茶一般放几克茶叶,品深茶官网根据多年专业研究与实践结果,制定了淡茶冲泡标准。在冲泡普洱茶淡茶时,茶叶的投放量是关键因素之一。淡茶冲泡标准旨在保持茶汤的清爽口感,同时充分展现普洱茶的独特风味。 根据《品深淡茶冲…

AMEYA360详解:蔡司利用纳米探针技术探索半导体微观电学性能

半导体器件尺寸不断缩小和复杂度增加,纳米探针(Nanoprobing)技术成为解决微观电学问题和优化器件性能的重要工具,成为半导体失效分析流程中越来越重要的一环。 随着功率半导体的快速发展,其厂商也开始密切关注纳米探针技术在PN结特性分析和掺…