opentelemetry笔记
span
https://github.com/open-telemetry/opentelemetry-cpp/blob/f987c9c094f276336569eeea85f17e361de5e518/sdk/src/trace/span.h
在 OpenTelemetry C++ 的 sdk/src/trace 目录中,不同的 span 定义和实现是为了支持追踪(Tracing)功能的多样化需求。以下是一些关键点来帮助您理解它们的区别:
Span 的核心概念
Span 是 OpenTelemetry 中的核心追踪单元,表示一次独立的操作或事件。
每个 Span 包含以下信息:
- 操作的名称
- 上下文信息(如 TraceId 和 SpanId)
- 开始和结束时间
- 属性(Attributes)和事件(Events)
- 链接(Links)
在不同文件中的 Span 定义
在 OpenTelemetry 的代码中,Span 有不同的实现和变体,用于适应多种场景:
API 层的 Span
定义在 api/include/opentelemetry/trace/span.h。
这是一个抽象类,定义了 Span 的基本接口,如 SetAttribute、AddEvent、End 等方法。
它提供了一个标准化的接口,供所有 Span 实现遵循。
SDK 层的 Span
定义在 sdk/src/trace/span.h 和实现中(如 span.cc)。
这是 API 层 Span 的具体实现,处理真正的追踪逻辑。
它负责:
记录和存储追踪数据。
与 Tracer 和 SpanProcessor 协同工作,将数据导出到后端。
默认的空操作 Span(DefaultSpan)
定义在 api/include/opentelemetry/trace/default_span.h。
用于在没有实际追踪上下文的情况下,提供一个占位的 Span 实现。
它不会记录任何数据,仅用于传播上下文。
设计背后的原因
抽象与实现分离:
API 层的 Span 是一个接口,定义了所有 Span 的通用行为。
SDK 层的 Span 是具体实现,负责处理数据。
灵活性与扩展性:
不同的 Span 实现可以适应不同的需求,比如实际追踪、空操作实现等。
性能优化:
默认的空操作 Span 减少了不必要的开销。
API 与SDK
API 层的含义
API(Application Programming Interface)层 是为开发者提供的接口,定义了功能的规范和使用方法:
-
作用:
- 提供统一的接口,供用户或其他模块调用。
- 隐藏实现的细节,只暴露功能定义。
- 例如,
opentelemetry::trace::Span
是一个抽象接口,定义了追踪单元的核心操作(如SetAttribute
、AddEvent
等)。
-
特点:
- 抽象化:API 层主要包含接口和定义,而不涉及具体实现。
- 独立性:可以独立于具体实现运行。
- 灵活性:允许不同的实现(如 SDK 层)以自己的方式实现这些接口。
-
示例:
在 OpenTelemetry 中,API 层定义了所有核心行为,例如Tracer
、Span
和SpanContext
,目的是为用户提供一个统一的追踪接口。
SDK 的含义
SDK(Software Development Kit) 层是 API 的具体实现,负责实现 API 中定义的功能:
-
作用:
- 提供 API 的具体实现,包括逻辑、数据存储、导出等。
- 负责和后端服务(如 OpenTelemetry Collector)交互。
- 例如,
sdk::trace::Span
是opentelemetry::trace::Span
的实现类,用于记录和管理追踪数据。
-
特点:
- 实现性:SDK 层实现了 API 的所有功能,提供具体的逻辑和行为。
- 可扩展性:允许用户配置不同的导出器、采样器等组件。
- 面向后端:将跟踪数据导出到后端进行存储和分析。
-
示例:
在 OpenTelemetry 中,sdk::trace::Tracer
和sdk::trace::Span
是 API 层Tracer
和Span
的具体实现。SDK 层实现了追踪数据的记录、处理和导出。
API 层与 SDK 层的关系
- API 层 定义了功能和行为,是用户与库之间的接口。
- SDK 层 实现了 API 的功能,负责具体逻辑和与后端的交互。
- 调用关系:用户通过 API 层调用功能,而这些功能的具体实现由 SDK 层提供。
类比
可以将 API 层和 SDK 层的关系比作一个家电:
- API 层:家电的遥控器,定义了开关、调节等功能。
- SDK 层:家电的内部组件,具体实现了遥控器的功能(如启动电机、调节温度等)。
Recordable
Recordable
是 OpenTelemetry C++ SDK 中的一个核心接口,用于表示可记录的数据结构,如日志记录或追踪(Tracing)数据。这是一个抽象类,具体实现取决于导出器(Exporter)或处理器(Processor)的需求。以下是关键点:
1. Recordable
的定义
- 头文件位置:
sdk/include/opentelemetry/sdk/trace/recordable.h
- 主要功能:
- 提供一个标准化的数据结构,用于存储追踪或日志记录的数据。
- 定义了一些通用方法,如设置属性、添加事件和链接等。
- 代码片段:
class Recordable { public:virtual ~Recordable() = default;virtual void SetIdentity(const opentelemetry::trace::SpanContext &span_context,opentelemetry::trace::SpanId parent_span_id) noexcept = 0;virtual void SetAttribute(nostd::string_view key,const opentelemetry::common::AttributeValue &value) noexcept = 0;virtual void AddEvent(nostd::string_view name,opentelemetry::common::SystemTimestamp timestamp,const opentelemetry::common::KeyValueIterable &attributes) noexcept = 0;virtual void AddLink(const opentelemetry::trace::SpanContext &span_context,const opentelemetry::common::KeyValueIterable &attributes) noexcept = 0;virtual void SetName(nostd::string_view name) noexcept = 0;virtual void SetTraceFlags(opentelemetry::trace::TraceFlags flags) noexcept = 0;virtual void SetStartTime(opentelemetry::common::SystemTimestamp start_time) noexcept = 0;virtual void SetDuration(std::chrono::nanoseconds duration) noexcept = 0; };
2. Recordable
的主要方法
SetIdentity
:
设置Recordable
的标识,包括SpanContext
和父级SpanId
。SetAttribute
:
设置Recordable
的属性(键值对)。AddEvent
:
添加事件(包括名称、时间戳和属性)。AddLink
:
添加链接到其他Span
。SetName
:
设置Recordable
的名称。SetTraceFlags
:
设置追踪标志。SetStartTime
和SetDuration
:
设置Recordable
的开始时间和持续时间。
3. 具体实现
Recordable
是一个抽象类,具体功能由不同的导出器实现,例如:- Zipkin 导出器:
exporters/zipkin/recordable.h
- 实现在
opentelemetry-cpp/exporters/zipkin/src/recordable.cc
- 提供了 Zipkin 格式的实现。
- 支持 JSON 格式输出。
- OTLP 导出器:
exporters/otlp/src/otlp_file_exporter.cc
- 提供了 OTLP 格式的实现。
- 支持 gRPC 和 HTTP 导出。
- Zipkin 导出器:
4. 与 SpanProcessor
的关系
Recordable
是SpanProcessor
的核心工具,用于将数据从内存中提取并格式化为导出器可用的形式。- 例如:
SpanProcessor::MakeRecordable
创建Recordable
的实例。SpanProcessor::OnStart
和SpanProcessor::OnEnd
使用Recordable
来处理Span
数据。
5. 总结
Recordable
是 OpenTelemetry 的一个核心抽象,用于在追踪和日志记录数据的生命周期中充当一个可记录的数据存储单元。它的具体实现由导出器(如 Zipkin 或 OTLP)决定,提供了灵活性以支持各种后端服务。如果需要进一步理解某个导出器的实现,可以查看它的具体代码文件。
项目架构
https://opentelemetry.opendocs.io/docs/specs/otel/overview/
OpenTelemetry C++ 项目是一个实现分布式追踪和指标采集的客户端库,支持多种后端系统。它的架构分为以下几个关键组件或层次,每个组件负责特定的功能:
1. API 层
API 层是开发者直接与 OpenTelemetry 交互的接口。它定义了一组抽象类和接口,允许开发者记录追踪(Tracing)数据和指标(Metrics),而无需了解底层实现。
- 关键文件:
opentelemetry/trace/span.h
:定义了Span
类,用于描述分布式追踪中的操作。opentelemetry/trace/tracer.h
:定义了Tracer
类,负责创建和管理Span
。opentelemetry/metrics
:用于指标的记录和管理。
- 职责:
- 提供开发者调用的接口,例如创建
Span
、设置属性、记录事件。 - 保持实现的独立性,允许使用不同的 SDK 或后端。
- 提供开发者调用的接口,例如创建
2. SDK 层
SDK 层是 API 的具体实现,负责将追踪数据和指标从内存中提取、处理,并通过导出器(Exporter)发送到后端。
- 关键文件:
sdk/trace/span.h
:实现了Span
的具体功能。sdk/trace/processor.h
:定义SpanProcessor
,用于处理和批处理Span
数据。sdk/metrics
:实现指标的采集和管理。
- 职责:
- 提供
Tracer
和Span
的实现。 - 管理配置(如采样器、处理器、导出器)。
- 将数据批量发送给后端。
- 提供
3. 导出器(Exporter)
导出器负责将追踪数据和指标发送到后端系统,例如 Zipkin、Jaeger、Prometheus 或 OpenTelemetry Collector。
- 关键文件:
exporters/zipkin
:实现 Zipkin 的导出功能。exporters/otlp
:实现 OpenTelemetry Protocol (OTLP) 的导出功能。
- 职责:
- 将
Recordable
(可记录的数据结构)转换为后端支持的格式(如 JSON 或 Protobuf)。 - 通过 HTTP、gRPC 或文件等方式发送数据。
- 将
4. 工具与兼容性层
nostd
(Non-Standard Library):- 提供了一些轻量级的工具类,例如
nostd::span
,用于兼容没有 C++17 支持的环境。
- 提供了一些轻量级的工具类,例如
common
:- 定义了一些通用的工具和数据结构,如属性值(AttributeValue)和时间戳(Timestamp)。
5. 测试与示例
- 测试:
- 提供了单元测试和集成测试,确保每个模块的功能正常。
- 测试代码存放在
api/test
和sdk/test
目录中。
- 示例:
- 提供了各种使用场景的示例,帮助开发者快速上手。
- 示例代码存放在
examples
目录中。
6. 项目目录结构
以下是项目目录结构的简要说明:
api
:API 层定义的接口和抽象类。sdk
:SDK 的具体实现,包括追踪和指标的处理。exporters
:支持的导出器模块(如 OTLP、Zipkin)。examples
:示例代码,演示如何使用 OpenTelemetry C++。common
:通用工具和数据结构。nostd
:非标准库的实现,用于兼容不同的 C++ 标准。tests
:测试代码,验证项目的正确性。
7. 架构工作流程
- 开发者调用 API:
- 使用
Tracer
创建Span
,并记录操作信息。
- 使用
- SDK 处理数据:
SpanProcessor
处理和存储Span
数据。
- 导出器发送数据:
- 数据通过导出器发送到后端系统。
- 后端分析:
- 后端系统(如 Zipkin、Jaeger)接收并分析追踪数据。
总结
OpenTelemetry C++ 项目通过模块化设计,将接口、实现和导出器分离,提供了高效、灵活的分布式追踪和指标采集方案。它的架构保证了可扩展性,允许用户根据需求配置或扩展功能。如果需要更深入的说明,可以指定某个模块或文件!
学习点
OpenTelemetry C++ 项目架构设计中有许多值得学习和借鉴的地方,特别是在构建灵活、高效、可扩展的分布式追踪和指标采集系统方面。以下是一些关键学习点:
1. 模块化设计
- 特点:
- 项目将功能分解为多个模块,包括 API 层、SDK 层、导出器(Exporter)和工具库(nostd, common)。
- 每个模块职责单一,易于维护和扩展。
- 学习点:
- 模块化设计使代码结构清晰,并允许开发者根据需要选择性地引入模块。
- 提供了灵活性,例如用户可以仅使用 API 层而不依赖具体的 SDK 实现。
2. API 和 SDK 分离
- 特点:
- API 层提供抽象接口,开发者可以面向接口编程。
- SDK 层实现了 API 的具体功能,并处理复杂的逻辑,如数据采样、批处理和导出。
- 学习点:
- 这种分层设计提高了代码的灵活性和可替换性。例如,用户可以用自定义的 SDK 替换默认实现,而无需修改 API 层代码。
3. 可插拔的导出器(Exporter)
- 特点:
- 项目支持多种导出器(如 Zipkin、Jaeger 和 OTLP),这些导出器实现了相同的接口(
SpanExporter
)。 - 用户可以根据需求选择或开发自己的导出器。
- 项目支持多种导出器(如 Zipkin、Jaeger 和 OTLP),这些导出器实现了相同的接口(
- 学习点:
- 使用接口和工厂模式设计导出器,使系统可以轻松扩展支持新的后端。
- 通过抽象与实现分离,增强了系统的适配能力。
4. 轻量级工具库(nostd)
- 特点:
- 提供了一些轻量级的工具类(如
nostd::span
、nostd::string_view
),以减少对外部库的依赖。 - 设计上兼容 C++11 和 C++14,适应了不同的编译环境。
- 提供了一些轻量级的工具类(如
- 学习点:
- 在需要兼容老旧环境时,可以通过实现简化版的标准库功能来支持更多用户场景。
5. 高效的并发支持
- 特点:
- 使用线程安全的数据结构和锁机制(如
std::mutex
)来保证多线程环境下的安全性。 - 例如,
BatchSpanProcessor
使用缓冲区和后台线程来批量导出数据,减少了对性能的影响。
- 使用线程安全的数据结构和锁机制(如
- 学习点:
- 在高性能应用中,通过批处理和异步操作可以有效减少运行时开销。
- 对并发访问进行严格的控制,避免数据竞争问题。
6. 灵活的配置和扩展机制
- 特点:
- 支持用户自定义配置(如采样器、处理器和导出器)。
- 提供了多种默认实现(如简单采样器和批处理器),同时允许用户扩展自己的实现。
- 学习点:
- 提供默认配置降低了用户的学习成本,而开放扩展接口又满足了高级用户的需求。
- 使用工厂模式生成对象(如
SpanProcessor::MakeRecordable
),进一步增强了灵活性。
7. 跨语言的设计一致性
- 特点:
- OpenTelemetry 是一个跨语言的项目,C++ 实现遵循了 OpenTelemetry 的整体设计规范,与其他语言(如 Go、Python)的实现保持一致。
- 学习点:
- 在多语言项目中,保持设计一致性有助于跨团队协作,并降低用户在不同语言中的学习成本。
8. 清晰的目录结构和文档
- 特点:
- 项目目录按照功能划分,如
api
、sdk
、exporters
、examples
和tests
。 - 提供了详细的文档和代码示例,帮助用户快速上手。
- 项目目录按照功能划分,如
- 学习点:
- 清晰的目录结构和完善的文档提升了项目的可维护性和可用性。
9. 测试覆盖与质量保证
- 特点:
- 提供了丰富的单元测试和集成测试,保证了模块的正确性。
- 测试覆盖了常见场景和边界情况。
- 学习点:
- 测试是高质量代码的保障,特别是在分布式系统中,测试可以帮助捕获潜在的复杂问题。
10. 遵循最佳实践和开源规范
- 特点:
- 遵循 Apache 2.0 开源协议,代码风格整洁,注释清晰。
- 使用 CMake 管理构建,支持多平台编译。
- 学习点:
- 遵循开源规范和最佳实践可以提升项目的可读性和社区参与度。
总结
OpenTelemetry C++ 项目的架构体现了模块化、灵活性和高性能的特点。这种设计值得学习,特别是在开发分布式系统、异步处理和可扩展性框架时,可以借鉴其 API/SDK 分离、可插拔设计和高效的并发处理等技术思想。
工厂模式
在 OpenTelemetry C++ 项目中,导出器(Exporter)的设计使用了接口和工厂模式,这种设计模式有助于实现模块化、灵活性和可扩展性。以下是具体解释:
1. 接口的使用
- 定义:接口是一种抽象类,提供了一组方法的定义,而不包含具体实现。
- 在导出器中的作用:
- 导出器实现了
SpanExporter
接口,该接口定义了导出追踪数据的标准方法。 - 用户可以通过使用接口操作导出器,而无需关心其具体实现。
- 导出器实现了
- 关键接口:
SpanExporter
(位于sdk/include/opentelemetry/sdk/trace/exporter.h
):class SpanExporter { public:virtual ~SpanExporter() = default;virtual std::unique_ptr<Recordable> MakeRecordable() noexcept = 0;virtual ExportResult Export(const nostd::span<std::unique_ptr<Recordable>> &spans) noexcept = 0;virtual bool Shutdown(std::chrono::microseconds timeout = (std::chrono::microseconds::max)()) noexcept = 0; };
MakeRecordable
:创建一个Recordable
(可记录的数据结构)。Export
:将一批追踪数据导出到后端。Shutdown
:关闭导出器并完成清理工作。
2. 工厂模式的使用
- 定义:工厂模式提供了一种创建对象的方式,用户只需要调用工厂方法,而不需要直接使用
new
操作符。 - 在导出器中的作用:
- 工厂模式用于创建导出器实例,如 Zipkin、OTLP 等。
- 用户可以通过工厂方法动态选择导出器的类型,而无需修改代码。
- 示例:
- 在某些导出器实现中,
MakeRecordable
方法就是一种工厂方法,用于生成Recordable
对象。例如:std::unique_ptr<sdk::trace::Recordable> ZipkinExporter::MakeRecordable() noexcept {return std::unique_ptr<sdk::trace::Recordable>(new ZipkinRecordable()); }
- 这里
ZipkinExporter
使用工厂方法创建一个ZipkinRecordable
对象,而用户无需直接调用new
。
- 这里
- 在某些导出器实现中,
3. 设计的优势
- 模块化:
- 不同的导出器(如 OTLP、Zipkin)实现了相同的接口,因此可以很容易替换或扩展新的导出器。
- 灵活性:
- 工厂模式允许动态创建对象,用户可以根据配置选择导出器类型,而无需修改代码。
- 可维护性:
- 通过接口分离定义和实现,降低了模块之间的耦合性,便于维护和测试。
- 可扩展性:
- 新的导出器只需实现接口,并注册到工厂中即可,无需修改现有代码。
4. 实际使用案例
假设用户想使用 Zipkin 导出器:
- 接口操作:
用户调用SpanExporter
定义的方法,例如Export
。 - 工厂创建:
Zipkin 导出器通过工厂方法MakeRecordable
创建Recordable
对象,并将其导出为后端可识别的数据格式。
总结
通过使用接口和工厂模式,OpenTelemetry C++ 项目实现了导出器的模块化和灵活性。接口定义了功能规范,工厂模式提供了动态创建对象的能力,使得用户可以轻松扩展和维护系统,同时支持多种后端。
高并发
OpenTelemetry C++ 项目在高并发环境下的设计,重点在于高效的数据收集、线程安全性以及批量处理机制。以下是对其高并发设计的详细分析:
1. 高效的并发数据收集机制
-
Span
的线程安全设计- 在多线程环境下,多个
Span
可能同时被创建和记录数据。 Span
的实现中使用了线程安全的机制(如std::mutex
),以确保在高并发环境下数据一致性。- 例如在
sdk::trace::Span
的实现中,使用了mutable std::mutex
锁来保护共享资源。
- 在多线程环境下,多个
-
Recordable
的抽象Recordable
是一个线程兼容的类,用于存储追踪数据。- 通过接口隔离数据操作逻辑,避免了直接操作共享资源所引发的竞争。
2. 批处理与异步处理
高并发系统中,频繁导出数据会导致性能下降,因此 OpenTelemetry C++ 使用批处理和异步处理来优化性能。
-
批处理(Batch Processing)
- OpenTelemetry 提供了
BatchSpanProcessor
,用于将多个Span
数据合并到批次中,再统一导出。 - 关键点:
- 使用了内部缓冲区(如循环队列)存储待导出的
Span
。 - 当缓冲区达到一定大小或超时时,会触发批量导出。
- 使用了内部缓冲区(如循环队列)存储待导出的
- 优点:
- 减少了对导出器的调用频率,降低了后端系统的压力。
- 提高了网络和处理的吞吐量。
- OpenTelemetry 提供了
-
异步处理
BatchSpanProcessor
使用后台线程异步处理数据:- 一个独立的线程定期检查缓冲区,批量发送数据到导出器。
- 使用条件变量(
std::condition_variable
)来唤醒工作线程,避免忙等(busy-waiting)。
- 优点:
- 避免了主线程阻塞,提高了整体系统的响应能力。
- 允许高并发的
Span
记录,不会受到导出操作的影响。
3. 线程安全的共享资源管理
-
锁的使用
- 在需要修改共享资源时(例如缓冲区或
Span
的属性),使用了std::mutex
或其他同步原语来保护资源。 - 例如,
BatchSpanProcessor
的缓冲区操作实现是线程安全的。
- 在需要修改共享资源时(例如缓冲区或
-
无锁设计
- 某些场景中,使用了无锁设计来减少锁竞争:
- 例如,在
Recordable
的创建和记录中,尽量减少对全局状态的依赖。 - 避免了频繁的上下文切换和锁等待,提高了并发性能。
- 例如,在
- 某些场景中,使用了无锁设计来减少锁竞争:
4. 线程池和资源分配
- 专用线程
BatchSpanProcessor
以及其他批处理器会启动专用线程处理异步任务,而不会影响主线程的性能。
- 线程池扩展
- 项目为高负载环境提供了灵活的扩展能力,用户可以通过配置调整线程池的大小或后台线程的行为。
5. 内存优化与延迟控制
高并发场景下,内存使用和延迟控制至关重要。
-
缓冲区限制
- 每个
SpanProcessor
都有最大队列大小和最大批量大小的限制,防止内存溢出。 - 当缓冲区满时,旧数据可能会被丢弃,从而保证系统的稳定性。
- 每个
-
超时控制
BatchSpanProcessor
支持自定义超时时间,当导出操作超过指定时间时会被强制终止。- 这避免了后台线程因单次导出失败而阻塞。
6. 高并发设计的优势总结
-
高效的数据收集和处理:
- 多线程环境下,
Span
和Recordable
的线程安全设计确保了数据一致性。 - 批处理和异步导出减少了导出器的调用频率,提高了整体吞吐量。
- 多线程环境下,
-
资源分配合理:
- 使用独立的后台线程,隔离了数据收集和导出的任务,避免相互影响。
-
灵活的配置和扩展:
- 用户可以通过调整批处理大小、队列限制和线程数等参数,适应不同的高并发场景。
-
可维护性和可扩展性:
- 通过接口和抽象层分离实现,允许用户替换或扩展不同的处理器和导出器。
学习启发
OpenTelemetry C++ 项目在高并发设计中的关键思想包括:
- 线程安全:在共享资源上使用合理的同步机制。
- 异步与批处理:减少阻塞操作,提高系统性能。
- 模块化设计:通过接口和抽象分离逻辑,增强扩展性。
- 灵活配置:允许用户根据实际需求调整系统行为。
这些设计思路可以广泛应用于高性能和高并发的系统开发中。
跨语言的设计一致性
https://opentelemetry.io/docs/concepts/signals/traces/#spans
QueryPerformanceFrequency
CSCI 4717 – High Performance Counter
High Resolution Counter
Let’s play around with the high resolution counter again. Remember that this counter counts the number of clock cycles of the system clock since the system was last powered up. The function we use to read this timer is QueryPerformanceCounter(). Since function reads the processor’s high resolution timer which is incremented once with every clock pulse of the processor’s clock, then for a 3.59 GHz machine, this timer is incremented approximately 3,590,000,000 times in a second. QueryPerformanceCounter() takes as its single parameter a pointer to a LARGE_INTEGER which you define in your code. This gives us a way to read how many clock cycles have occurred since the machine was turned on.
LARGE_INTEGER current_time;
QueryPerformanceCounter(¤t_time);
The number returned by QueryPerformanceCounter() is huge and not very useful for timing at the “seconds” level. As I mentioned earlier, it is incremented once with every pulse of the system clock. If we knew the system clock frequency, we could figure out how many seconds had passed since turning on the machine. This can be done with QueryPerformanceFrequency(). This function returns the frequency of the processor once again using a LARGE_INTEGER passed as a pointer for the function’s only parameter.
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
Dividing the counter value by the frequency will convert the time to seconds. Dividing the counter value by the frequency divided by 1,000 will convert the time to milliseconds. Dividing the counter value by the frequency divided by 1,000,000 will convert the time to microseconds and so on.
Laboratory Exercise
In today’s exercise, we will be using the counter to measure time. For the most part, we will be measuring time in microseconds. Begin by creating a console application in Visual Studio 2005. Below is some sample code that should work well for a template as we go through some of these examples. Remember that LARGE_INTEGER is a UNION, so to access the value stored in it, you must define the way you want the data returned. To do this, use the QuadPart component.
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include "Windows.h"using namespace std;int main( )
{LARGE_INTEGER current, frequency;QueryPerformanceFrequency(&frequency);QueryPerformanceCounter(¤t);cout << current.QuadPart/(frequency.QuadPart/1000000) << " uS have passed since resetting the high performance counter.\n";return 0;
}
Today, we will see if we can get some semi-accurate measurements of the following programming functions.
Time to read the high performance counter
Time to perform a function call
Time to return from a function call
Time between interruptions from the O/S
Comparison between times to call cout and printf
Comparison between times to perform recursive and non-recursive functions
C++ Windows时间函数 QueryPerformanceCounter()与QueryPerformanceFrequency()
https://zhuanlan.zhihu.com/p/532434005
相关文章:
opentelemetry笔记
span https://github.com/open-telemetry/opentelemetry-cpp/blob/f987c9c094f276336569eeea85f17e361de5e518/sdk/src/trace/span.h 在 OpenTelemetry C 的 sdk/src/trace 目录中,不同的 span 定义和实现是为了支持追踪(Tracing)功能的多样…...
【JavaScript】二十一、日期对象
文章目录 1、实例化日期对象2、相关方法3、时间戳4、案例:毕业🎓倒计时效果 1、实例化日期对象 获得当前时间 const date new Date()获得指定时间 const date new Date(2025-4-14 20:46:00) console.log(date)2、相关方法 方法作用说明getFullYear…...
GIT工具学习【1】:新安装git预操作
目录 1.写在前面2.为常用指令配置别名3.初始化4.解决中文乱码问题 1.写在前面 新安装git命令后,需要一些设置会用的比较的顺畅。 这篇文章只要跟着做即可,至于原理,后面会写清楚的。 2.为常用指令配置别名 #新建一个.bashrc touch ~/.bash…...
docker安装ES
ES安装步骤 1. 创建docker网络,使其docker内部通信 2. 下载 | 导入镜像文件(ES Kibana) 3. 创建容器,并访问 4. 安装Ik分词器(es对中文并不友好,所以需要安装IK分词使其适配中文) 1. 创建docke…...
【控制学】控制学分类
【控制学】控制学分类 文章目录 [TOC](文章目录) 前言一、工程控制论1. 经典控制理论2. 现代控制理论 二、生物控制论三、经济控制论总结 前言 控制学是物理、数学与工程的桥梁 提示:以下是本篇文章正文内容,下面案例可供参考 一、工程控制论 1. 经典…...
人工智能应用开发中常见的 工具、框架、平台 的分类、详细介绍及对比
以下是人工智能应用开发中常见的 工具、框架、平台 的分类、详细介绍及对比: 一、工具(Tools) 定义:用于完成特定任务的软件或库,通常专注于开发流程中的某个环节(如数据处理、模型调试、部署等ÿ…...
Linux磁盘格式化(mkfs、mkfs.xfs、mkfs.ext4)、Linux文件系统的校验(xfs_repair、fsck_ext4)
在Linux系统中,磁盘格式化和文件系统校验是系统管理的重要任务。以下是关键步骤和命令的总结: 磁盘格式化 1. 选择文件系统类型 XFS:适用于大文件和高并发场景,支持高性能和扩展性。ext4:成熟稳定的通用文件系统,适合大多数场景。2. 格式化命令 通用格式: sudo mkfs -…...
Android学习总结之git篇
Git 的原理时,你可以从数据结构、对象存储、引用管理、分支与合并等方面结合源码进行分析。以下是详细介绍: 1. 基本数据结构和对象存储 Git 底层主要基于四种对象来存储数据:blob(数据块)、tree(树&…...
Python基础语法——类型
目录 类型的意义动态类型静态类型 类型的意义 不同的类型,占用的内存空间是不同的. 占几个字节 int 默认是 4 个字节.动态扩容 float 固定 8 个字节 bool 一个字节就足够了 str 变长的 不同的类型,对应能够进行的操作也是不同的 int/float, “” “-” “ * ” “/”——不能使…...
vue2中基于el-select封装一个懒加载下拉框
需求 当下拉选项的数据量过大时,后端接口是分页格式返回数据。 解决方案 自定义封装一个懒加载下拉组件,每次滚动到底部时自动获取下一页数据,这样可有效防止数据量过大时造成组件卡顿。 具体实现步骤 1、创建懒加载下拉选择组件 <t…...
uniapp的h5,打开的时候,标题会一闪而过应用名称,再显示当前页面的标题
问题: 微信小程序,通过webview打开了uniapp创建的h5,但是打开h5时,会先显示h5的应用名称,然后才切换为该页面的标题。 过程: 查过很多资料,有说修改应用名称,有说设置navigationS…...
HarmonyOS 5 开发环境全解析:从搭建到实战
鸿蒙来了,从 1.0 到 5.0,它不再只是“华为的操作系统”,而是万物互联生态的核心驱动。作为开发者,你准备好拥抱这个全新时代了吗? 你是否还在犹豫:HarmonyOS 5 开发门槛高不高?该用 DevEco Stu…...
2.2 函数返回值
1.回顾def def sum(x,y): return xy res sum(10,20) #调用函数 print(res) 2.函数的三个重要属性 -函数的类型:function -函数的ID:16进制的整数数值 -函数的值:封装在函数中的数据和代码 # - 函数是一块内存空间,通过…...
OpenAI发布GPT-4.1:开发者专属模型的深度解析 [特殊字符]
最近OpenAI发布了GPT-4.1模型,却让不少人感到困惑。今天我们就来深入剖析这个新模型的关键信息! 重要前提:API专属模型 💻 首先需要明确的是,GPT-4.1仅通过API提供,不会出现在聊天界面中。这是因为该模型主…...
Cython中操作C++字符串
使用Cython开发Python扩展模块-CSDN博客中文末对python代码做了部分C优化,并提及未对字符串类型做优化,并且提到如果不是真正搞懂了C字符串的操作和Python的C API中与字符串相关的知识,最好不要动Python中的字符串类型。为了搞明白在Cython中…...
Dify插件内网安装,解决Dify1.x插件安装总失败问题,手把手教你暴力破解:从镜像源到二进制打包全攻略
背景 自从dify升级到1.0以后,所有的工具和模型都改成了插件化,需要进行插件的安装。在手撕Dify1.x插件报错!从配置到网络到Pip镜像,一条龙排雷实录 已经指出了dify在线安装插件的各种问题。 首发地址 在前面的几个版本中&…...
二极管详解:特性参数、选型要点与分类
一、二极管的基本定义 二极管(Diode) 是由半导体材料(如硅、锗)构成的双端器件,核心特性是单向导电性。其结构基于PN结,正向偏置导通,反向偏置截止。 核心功能: 整流(交…...
BufferedOutputStream 终极解析与记忆指南
BufferedOutputStream 终极解析与记忆指南 一、核心本质 BufferedOutputStream 是 Java 提供的缓冲字节输出流,继承自 FilterOutputStream,通过内存缓冲区显著提升 I/O 性能。 核心特性速查表 特性说明继承链OutputStream → FilterOutputStream → …...
Google政策大更新:影响金融,新闻,社交等所有类别App
Google Play 4月10日 迎来了2025年第一次大版本更新,新政主要涉及金融(个人贷款),新闻两个行业。但澄清内容部分却使得所有行业都需进行一定的更新。下面,我们依次从金融(个人贷款),…...
【Linux网络与网络编程】10.网络层协议IP
前言 我们之前谈的主机B把数据传递给主机C过程都是黑盒式的,即并没有考虑它的中间过程。本篇博客和下一篇博客将要考虑的问题是:主机B和主机C并不是直接连接的,主机B想要把数据传输给主机C需要经过若干路由器的。我们就引出了两个问题&#x…...
Docker 搭建 RabbitMQ
Docker 搭建 RabbitMQ 前言一、准备工作二、设置目录结构三、编写启动脚本四、Host 网络模式 vs Port 映射模式1. Host 网络模式2. Port 映射模式 五、端口配置对比六、配置示例七、查看与管理八、扩展与高可用九、常用命令 前言 在现代微服务与分布式架构中,Rabbi…...
浏览器自动化检测对抗:修改navigator.webdriver属性的底层实现
一、背景介绍:你被自动化检测拒之门外了吗? 在使用 Selenium 或 Playwright 等浏览器自动化工具爬取数据时,经常会遇到「被检测」问题,尤其像 Amazon 这样反爬策略严密的网站。常见的检测机制之一就是检查 JavaScript 中的 navig…...
聊聊Spring AI Alibaba的DocumentParser
序 本文主要研究一下Spring AI Alibaba的DocumentParser DocumentParser spring-ai-alibaba-core/src/main/java/com/alibaba/cloud/ai/document/DocumentParser.java public interface DocumentParser {/*** Parses a given {link InputStream} into a {link Document}. T…...
用css给div列表加个序号
用 CSS 的 counter 相关属性来为列表添加序号。以下是具体的代码,我将以 HTML 文件的形式提供,并且会运行展示效果: .as-div {// counter-reset: my-counter; /* 计数器名称是my-counter */// counter-reset: small-apple; /* 计数器名称是s…...
CSS标签选择器与类选择器
CSS标签选择器 标签选择器(元素选择器)是最基本的选择器之一,用于选择HTML文档中的特定标签元素并应用样式。它使用HTML标签名称作为选择器,选择匹配该标签的所有元素。 作用:通过HTML标签名选择元素 以下是CSS标签选…...
(51单片机)LCD显示日期时间时钟(DS1302时钟模块教学)(LCD1602教程)
目录 源代码 main.c LCD1602.c LCD1602.h DS1302.c DS1302.h 代码解析与教程: LCD1602模块 DS1302模块 效果视频: 源代码 如上图将5个文放在Keli5 中即可,然后烧录在单片机中就行了 烧录软件用的是STC-ISP,不知道怎么安装的…...
编译原理(自考13007)
资源内容 大纲 概述...
C#Winform程序将子窗体嵌入容器方法
private void OpenForm(Form childFrom) { //首先判断容器中是否有其他的窗体 foreach (Control item in this.panelRight.Controls) { if (item is Form) { ((Form)item).Close(); } } //嵌入新的窗体 childFrom.TopLevel false;//将子窗体设置成非顶级控件 childFrom.Parent…...
WPS JS宏编程教程(从基础到进阶)-- 第八部分:字符串技术与WPS结合应用
目录 第8章 字符串技术与WPS结合应用8-1 字符串的3种引用方式场景:动态生成报表标题三种引用方式对比代码解析表模板字符串核心优势8-2 字符串处理之切片与搜索场景:提取身份证中的出生年份三大截取方法对比方法选择指南索引搜索实战8-3 字符串处理之修改与填充场景:规范商品…...
WPS Office安卓版文档编辑功能与兼容性评测【高效编辑】
一、界面设计与操作体验 WPS Office安卓版采用简洁直观的界面设计,首页默认展示近期文档列表,支持一键新建文档、表格或演示文稿。整体操作逻辑与PC端保持一致,新用户也能快速上手。编辑工具栏设计合理,常用功能如字体设置、段落…...
【经验记录贴】使用配置文件提高项目的可维护性
mark一下。 整体修改前后如下: 课题: 在项目中有一个支持的文件类型的FILE_TYPE的定义, 这个是写死在主程序中,每次增加可以支持的文件类型的时候,都需要去修改主程序中这个FILGE_TYPE的定义。 主程序修改其实不太花时…...
传统建筑管理人力成本高,楼宇自控系统如何有效降低运营成本
在传统建筑管理模式下,人力成本一直居高不下,成为建筑运营方沉重的负担。从设备的日常巡检、维护,到环境的调控以及能源的管理,无一不需要大量人力投入。然而,随着科技的飞速发展,楼宇自控系统应运而生&…...
RabbitMQ demo案例
1. 下载和安装 RabbitMQ RabbitMQ 依赖 Erlang 运行时,所以得先装 Erlang,再装 RabbitMQ。下面以 Ubuntu 为例,Windows 和 macOS 也顺便提一下。 1.1 安装 Erlang RabbitMQ 需要 Erlang 支持,先装它。 Windows: 去 Erl…...
第T8周:猫狗识别
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍖 原作者:K同学啊 第T8周:猫狗识别 tf.config.list_physical_devices(“GPU”),用于检测当前系统是否有可用的 GPU,并将结果存入 gpus 变量。…...
旅游特种兵迪士尼大作战:DeepSeek高精准路径优化
DeepSeek大模型高性能核心技术与多模态融合开发 - 商品搜索 - 京东 随着假期的脚步日渐临近,环球影城等备受瞩目的主题游乐场,已然成为大人与孩子们心中不可或缺的节日狂欢圣地。然而,随之而来的庞大客流,却总让无数游客在欢乐的…...
ffmpeg-将多个视频去掉音频 然后切片组合成一个视频,再将新视频配置上新的音频
需求分解 1、去除原视频的音频轨道。 2、对去掉音频的视频进行切片。 3、将多个视频切片合并为一个新视频。 4、给新的视频添加新的音频轨道。 去除视频音频 要去除视频中的音频,只需使用以下命令 ffmpeg -i input1.mp4 -an -c:v copy output1_no_audio.mp4解释&a…...
05-微服务可观测性体系建设:从日志、监控到链路追踪实战指南
微服务可观测性体系建设:从日志、监控到链路追踪实战指南 一、可观测性:微服务架构的 “神经系统” 1.1 为什么需要可观测性? 在分布式微服务架构中,服务节点可能达数百个,请求链路跨越多服务、数据库、消息队列&am…...
音视频小白系统入门笔记-0
本系列笔记为博主学习李超老师课程的课堂笔记,仅供参阅 音视频小白系统入门课 音视频基础ffmpeg原理 绪论 ffmpeg推流 ffplay/vlc拉流 使用rtmp协议 ffmpeg -i <source_path> -f flv rtmp://<rtmp_server_path> 为什么会推流失败? 默认…...
基于 PyTorch 的 LSTM 实现降雨量预测
基于 PyTorch 的 LSTM 实现降雨量预测示例。包括数据准备、模型定义、训练和预测等。 文章目录 1. 数据准备:2. 模型定义:3. 训练过程:4. 预测和评估:5. 可视化:代码实现1. 数据准备: 使用随机生成的数据作为示例,实际应用中请替换为真实数据。数据被归一化到 [0, 1] 范…...
Spring-Bean的生命周期
一、什么是Bean生命周期? Spring容器中的Bean从创建到销毁的完整过程被称为Bean生命周期,包含实例化→属性注入→初始化→使用→销毁五个核心阶段。Spring提供了丰富的扩展点,允许开发者在各阶段插入自定义逻辑。 二、Bean生命周期全流程&am…...
AI大模型如何重塑科研范式:从“假说驱动”到“数据涌现”
📝个人主页🌹:慌ZHANG-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、引言:科研进入“模型共研”时代 传统科研范式通常以“假设→实验→验证→理论”的方式推进,这一经典路径建立在人类的认知能力与逻辑推理基础上。然而,随着数据规模的爆炸式增长与知识系统的高度复杂…...
yml文件上传并映射到实体类
文章目录 功能背景功能需要前端开发组件选用组件嵌套和参数绑定上传逻辑示例 后端开发接收逻辑解析逻辑省流纯手动实现(不建议) 功能背景 开发一个配置文件解析功能,需要兼容老版本的配置文件。 功能需要 前端:两个配置文件分别…...
What are the advantages of our neural network inference framework?
What are the advantages of our neural network inference framework? 1. Background2. What are the advantages of our neural network inference framework?References 1. Background Let me introduce /ˌɪntrəˈdjuːs/ the background /ˈbkɡraʊnd/ first. Today…...
猿辅导集团推首个教育AI范式小猿AI 聚焦家校应用场景发布3款新品
近两年,通用大模型呈爆发式发展,垂类AI遭遇“技术平替”危机。 4月15日,猿辅导集团在“小猿AI暨智能硬件战略发布会”上,正式推出首个教育AI范式——“小猿AI”,并发布覆盖家校两端的“软件应用智能终端通识课程”三位…...
10【模块学习】LCD1602(二):6路温度显示+实时时钟
项目:6路温度显示实时时钟 1、6路温度显示①TempMenu.c文件的代码②TempMenu.h文件的代码③main.c文件的代码④Timer.c文件的代码⑤Delay.c文件的代码⑥Key.c文件的代码 2、实时时钟显示①BeiJingTime.c文件的代码②BeiJingTime.h文件的代码③main.c文件的代码如下④…...
Embedding在RAG中的核心作用及其几何类比-来自DeepSeek
1. 核心概念映射 Embedding的本质:将文本、图像等非结构化数据转化为高维空间中的坐标点(向量),例如: 句子A → 向量 [0.2, -1.5, 3.0, ..., 0.7](假设维度为768) 句子B → 向量 [0.3, -1.4, 2…...
前端快速入门——JavaScript函数、DOM
1.JavaScript函数 函数是一段可重复使用的代码块,它接受输入(参数)、执行特定任务,并返回输出。 <scricpt>function add(a,b){return ab;}let cadd(5,10);console.log(c); </script>2.JavaScript事件 JavaScript绑定事件的方法࿱…...
AOSP14 Launcher3——最近任务TaskViewSimulator详解
前言:TaskViewSimulator 这个类在最近任务中起到了一个非常重要的作用。 从字面意思上理解,这个单词是由TaskViewSimulator组合而来,字面意思就是TaskView的模拟器,顾名思义,就是一个用来模拟TaskView的类。 为什么要模…...
层次式架构核心:中间层的功能、优势与技术选型全解析
层次式架构中的中间层是整个架构的核心枢纽,承担着多种重要职责,在功能实现、优势体现以及技术选型等方面都有丰富的内容,以下为你详细介绍: 一、功能 1.业务逻辑处理 复杂规则运算:在许多企业级应用中,…...
MySQL主从同步原理及面试回答
1. 什么是主从结构 主从复制、读写分离(分库)解决的是访问的压力 2. Mysql主从复制的原理 Mysql主从复制的核心是binlog日志文件(二进制日志文件) 二进制日志(BINLOG)记录了所有的 DDL(数据定…...