语音分帧简述

news2024/10/7 16:16:10

目录

1. 分帧

1.1 非整齐分帧

1.2 整齐分帧

2. 示例代码


1. 分帧

问题1:总帧数如何计算?

记符号N为语音总长度,FRAME_LEN为帧长,OVERLAP_LEN为帧与帧之间的重叠部分,STEP_LEN为帧移(步长)。则总帧数N_Frames计算如下:


因为OVERLAP_LEN=FRAME_LEN-STEP_LEN

所以有:

N-FRAME_LEN可以看成一个常数。因此帧移越大,重叠部分就越小,总帧数就越小,反之;当帧移最大等于帧长的时候,式子变为:


此时就变成了均分了,而不是重叠分割了。

重叠分割的情况下,帧移的选择也影响整段语音分帧的结果,而实时语音处理中一般取N为256的整数倍。

问题2:关于输入和输出

重叠输入,按STEP_LEN输出。

1.1 非整齐分帧

非整齐分帧的情况下,有数据丢失。首先是输入,取帧数据的时候没法取到,其次是考虑到输出。例:N=2048,FRAME_LEN=256,当STEP_LEN=28+8=36时。总帧数N_Frames=(1792/36)+1=50,最后一帧的起始位置:49x36=1764,取最后一帧256个点,结果是1764+256=2020,即最后2048-2020=28个点没法取到。

 

1.2 整齐分帧

例:N=2048,FRAME_LEN=256,当STEP_LEN=128时,可以分为15帧(帧索引是0~14),刚好能把所有的点都取到,最后一个帧的起始位置:14x128=1792,再取一帧长256,刚好就是2048。由此类推,以下帧移,都能整齐分帧:

14x128=1792

28x64=1792

56x32=1792

112x16=1792

224x8=1792

第一列就是N_Frame,第二列就是帧移STEP_LEN。帧移越小,分的帧越多,计算量也就越大。一般取50%的重叠,即帧移和帧重叠各占50%。

 注:最后一帧全部输出即可。

2. 示例代码

#if 1
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "baselib.h"
#include "win_fun.h"

typedef unsigned char	uint8_t;

#define FRAME_LEN (256)
#define STEP_LEN (128)
//#define STEP_LEN (64)
//#define STEP_LEN (32)
//#define STEP_LEN (16)
//#define STEP_LEN (8)
#define OVERLAP_LEN (FRAME_LEN-STEP_LEN)

#define BLK_INPUT_LEN (4096)
//#define BLK_INPUT_LEN (8192)

static const float win[FRAME_LEN]={
	0.080000, 0.080140, 0.080558, 0.081256, 0.082232, 0.083487, 0.085018, 0.086825, 0.088908, 0.091264, 0.093893, 0.096793, 0.099962, 0.103398, 0.107099, 0.111063, 0.115287, 0.119769, 0.124506, 0.129496, 0.134734, 0.140219, 0.145946, 0.151913, 0.158115, 0.164549, 0.171211, 0.178097, 0.185203, 0.192524, 0.200056, 0.207794,
	0.215734, 0.223871, 0.232200, 0.240716, 0.249413, 0.258287, 0.267332, 0.276542, 0.285912, 0.295437, 0.305110, 0.314925, 0.324878, 0.334960, 0.345168, 0.355493, 0.365931, 0.376474, 0.387117, 0.397852, 0.408674, 0.419575, 0.430550, 0.441591, 0.452691, 0.463845, 0.475045, 0.486285, 0.497557, 0.508854, 0.520171, 0.531500,
	0.542834, 0.554166, 0.565489, 0.576797, 0.588083, 0.599340, 0.610560, 0.621738, 0.632866, 0.643938, 0.654946, 0.665885, 0.676747, 0.687527, 0.698216, 0.708810, 0.719301, 0.729684, 0.739951, 0.750097, 0.760115, 0.770000, 0.779745, 0.789345, 0.798793, 0.808084, 0.817212, 0.826172, 0.834958, 0.843565, 0.851988, 0.860222,
	0.868261, 0.876100, 0.883736, 0.891163, 0.898377, 0.905373, 0.912148, 0.918696, 0.925015, 0.931100, 0.936947, 0.942554, 0.947916, 0.953030, 0.957894, 0.962504, 0.966857, 0.970952, 0.974785, 0.978353, 0.981656, 0.984690, 0.987455, 0.989948, 0.992168, 0.994113, 0.995782, 0.997175, 0.998290, 0.999128, 0.999686, 0.999965,
	0.999965, 0.999686, 0.999128, 0.998290, 0.997175, 0.995782, 0.994113, 0.992168, 0.989948, 0.987455, 0.984690, 0.981656, 0.978353, 0.974785, 0.970952, 0.966857, 0.962504, 0.957894, 0.953030, 0.947916, 0.942554, 0.936947, 0.931100, 0.925015, 0.918696, 0.912148, 0.905373, 0.898377, 0.891163, 0.883736, 0.876100, 0.868261,
	0.860222, 0.851988, 0.843565, 0.834958, 0.826172, 0.817212, 0.808084, 0.798793, 0.789345, 0.779745, 0.770000, 0.760115, 0.750097, 0.739951, 0.729684, 0.719302, 0.708810, 0.698216, 0.687527, 0.676747, 0.665885, 0.654946, 0.643938, 0.632866, 0.621738, 0.610560, 0.599340, 0.588083, 0.576797, 0.565489, 0.554166, 0.542833,
	0.531500, 0.520171, 0.508854, 0.497557, 0.486285, 0.475045, 0.463845, 0.452692, 0.441591, 0.430550, 0.419575, 0.408674, 0.397852, 0.387117, 0.376474, 0.365931, 0.355493, 0.345168, 0.334960, 0.324877, 0.314925, 0.305110, 0.295437, 0.285912, 0.276542, 0.267331, 0.258287, 0.249413, 0.240716, 0.232200, 0.223871, 0.215734,
	0.207794, 0.200056, 0.192524, 0.185203, 0.178097, 0.171211, 0.164549, 0.158115, 0.151913, 0.145947, 0.140219, 0.134734, 0.129496, 0.124506, 0.119769, 0.115287, 0.111063, 0.107099, 0.103398, 0.099962, 0.096793, 0.093893, 0.091265, 0.088908, 0.086825, 0.085018, 0.083487, 0.082232, 0.081256, 0.080558, 0.080140, 0.080000,
};

//float winGain;
//int zero_cnt;
//int zero_idx;
void voice_frame(short *x, int Nframes, short *xout, int blk_index);

int main(void)
{
	int i, j;
	int inputdata_length;
	struct timeval start, end;
	int timeuse;
	FILE* input_ptr = NULL;
	FILE* output_ptr = NULL;

	input_ptr = fopen("80k.pcm", "r");
	if (!input_ptr) {
		printf("open input stream fail\n");
		return -1;
	}

	fseek(input_ptr, 0, SEEK_END);
	inputdata_length = ftell(input_ptr);
	printf("inputdata_length:%d\n", inputdata_length);
	rewind(input_ptr);

	uint8_t* all_in_dat = (uint8_t*)calloc(inputdata_length, sizeof(uint8_t));
	uint8_t* all_out_dat = (uint8_t*)calloc(inputdata_length, sizeof(uint8_t));

	uint8_t* blk_input_dat = (uint8_t*)calloc(BLK_INPUT_LEN, sizeof(uint8_t));
	uint8_t* blk_output_dat = (uint8_t*)calloc(BLK_INPUT_LEN, sizeof(uint8_t));

	int count = fread(all_in_dat, sizeof(uint8_t), inputdata_length, input_ptr);
	printf("count:%d\n", count);
	rewind(input_ptr);

	int in_dat_len=BLK_INPUT_LEN/2;
	int out_dat_len=in_dat_len;
	printf("in_dat_len:%d\n", in_dat_len);
	short* in_dat = (short*)calloc(in_dat_len, sizeof(short));
	short* out_dat = (short*)calloc(out_dat_len, sizeof(short));

	int all_block=inputdata_length/BLK_INPUT_LEN;
	printf("all_block:%d\n", all_block);

	//int Nframes= in_dat_len/OVERLAP_LEN-1;
	int Nframes= (in_dat_len-FRAME_LEN)/STEP_LEN+1;
	printf("a block can div to Nframes:%d\n", Nframes);

//	for(i=0; i<FRAME_LEN; i++){
//		winGain+=win[i];
//	}
//	winGain=STEP_LEN/winGain;	//normalization gain for overlap+add with 50% overlap
//	printf("winGain:%f\n", winGain);

	int block_index, arr_index;

	for (block_index=0; block_index<all_block; block_index++) {
		//分块
		for (arr_index=0; arr_index<BLK_INPUT_LEN; arr_index++) {

			blk_input_dat[arr_index]=all_in_dat[block_index*(BLK_INPUT_LEN)+arr_index];
		}

		//init input
		for(i=0, j=0; i<in_dat_len; i++) {
			in_dat[i]=(blk_input_dat[j+1]<<8|blk_input_dat[j]);
			j=j+2;
		}
#if 0
		voice_frame(in_dat, Nframes, out_dat, block_index);
#else
		gettimeofday(&start, NULL);
		voice_frame(in_dat, Nframes, out_dat, block_index);
		gettimeofday(&end, NULL);
		timeuse = 1000000 * ( end.tv_sec - start.tv_sec ) + end.tv_usec - start.tv_usec;
		printf("time=%.10fs\n", (double)timeuse/1000000);
#endif

#if 0
		/*非整齐分帧,帧尾只能舍去(相当于丢失了信息)*/
		/*非整齐分帧, 比如:STEP_LEN=40 */
		memset(out_dat, 0, out_dat_len);
		zero_cnt=0;
		voice_frame(in_dat, Nframes, out_dat, block_index);
		for(i=0, j=0; i<out_dat_len; i++) {
			//printf("%d:%d\n", i, out_dat[i]);
			if(out_dat[i]==0) {
				if(zero_cnt>5)
					zero_cnt++;
				else {
					if(out_dat[i+1]==0 && out_dat[i+2]==0) {
						zero_cnt++;
					}
				}
			}
		}

		if(zero_cnt!=0)
			printf("zero_idx:%d, zero_cnt:%d\n",out_dat_len-zero_cnt, zero_cnt);
#endif

#if 0
		for(i=0; i<in_dat_len; i++)
			out_dat[i]=in_dat[i];
#endif

		for(i=0, j=0; i<out_dat_len; i++) {
			blk_output_dat[j]=out_dat[i]&0xff; //low 8bit
			blk_output_dat[j+1]=((out_dat[i]>>8)&0xff); //high 8bit
			j=j+2;
		}

		//整合
		for (arr_index=0; arr_index<BLK_INPUT_LEN; arr_index++) {
			all_out_dat[block_index*BLK_INPUT_LEN+arr_index]=blk_output_dat[arr_index];
		}
	}

	output_ptr = fopen("output80k.pcm", "wb");
	if (!output_ptr) {
		printf("open output stream fail\n");
		return -1;
	}

	fwrite(all_out_dat, sizeof(uint8_t), inputdata_length, output_ptr);

	free(all_in_dat);
	free(all_out_dat);
	free(in_dat);
	free(out_dat);
	free(blk_input_dat);
	free(blk_output_dat);
	fclose(input_ptr);
	fclose(output_ptr);

	return 0;
}

float one_in_dat[FRAME_LEN];
float one_in_dat_i[FRAME_LEN];
float res_dat[FRAME_LEN];
float one_out_dat[STEP_LEN];

void voice_frame(short *x, int Nframes, short *xout, int blk_index)
{
	int i, /*j,*/ k, n;

//	printf("blk_index:%d, Nframes:%d\n\n", blk_index, Nframes);

	if(blk_index==0)
	{
		//printf("the first block, do somthing init\n");
		//
	}

	//=========================    Start Processing   ===============================
	for(n=0, k=0; n<Nframes; n++) {
		/*input*/
		for(i=0; i<FRAME_LEN; i++) {
			one_in_dat[i]=(x[k+i]/32768.0)*win[i];
			//one_in_dat[i]=(x[k+i]/32768.0);
			//one_in_dat[i]=x[k+i];
		}

		/*process*/
		memset(one_in_dat_i, 0, FRAME_LEN);
		baselib_fft(one_in_dat, one_in_dat_i, 1, FRAME_LEN);
		baselib_fft(one_in_dat, one_in_dat_i, -1, FRAME_LEN);
		for(i=0; i<FRAME_LEN; i++)
			res_dat[i]=one_in_dat[i]/win[i];

		/*output*/
		if(n==Nframes-1) {
			for(i=0; i<FRAME_LEN; i++){
				xout[k+i]=(short)(res_dat[i]*32768.0);
				//xout[k+i]=res_dat[i];
			}
			return;
		}

		for(i=0; i<STEP_LEN; i++){
			one_out_dat[i]=res_dat[i];
		}

		for(i=0; i<STEP_LEN; i++){
			xout[k+i]=(short)(one_out_dat[i]*32768.0);
			//xout[k+i]=one_out_dat[i];
		}

		//update step
		k=k+STEP_LEN;
	}

}
#else
/*Linux平台下,计算一段代码的运行时长*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include "cmath.h"

int int_cal()
{
    int i,j;
    int v;
    for (i = 0; i < 5000; i++) {
        for (j = 0; j < 500; j++) {
            v = Pow(i + j,  i + j);
            //v = 1.1 + i + j+2.2 + i + j;
        }
    }

	return v;
}

int main()
{
    struct timeval start, end;
    int timeuse;

    gettimeofday(&start, NULL);
    sleep(2);
    gettimeofday(&end, NULL);
    timeuse = 1000000 * ( end.tv_sec - start.tv_sec ) + end.tv_usec - start.tv_usec;
    printf("time=%.3fs\n", (double)timeuse/1000000);

    gettimeofday(&start, NULL);
    int_cal();
    gettimeofday(&end, NULL);
    timeuse = 1000000 * ( end.tv_sec - start.tv_sec ) + end.tv_usec - start.tv_usec;
    printf("time=%.3fs\n", (double)timeuse/1000000);
}
#endif

注:代码中有数据归一化,加窗,然后是FFT/IFFT。输入是一个长为80k的音频,分段输入算法再输出(2k输入,2k输出)。

X86平台上运行的结果:

inputdata_length:81920

count:81920

in_dat_len:2048

all_block:20

a block can div to Nframes:15

time=0.0002560000s

time=0.0002500000s

time=0.0002510000s

time=0.0002500000s

time=0.0002500000s

time=0.0002500000s

time=0.0002490000s

time=0.0002670000s

time=0.0002500000s

time=0.0002500000s

time=0.0002500000s

time=0.0002500000s

time=0.0002500000s

time=0.0002500000s

time=0.0002500000s

time=0.0002500000s

time=0.0002500000s

time=0.0002500000s

time=0.0002500000s

time=0.0002500000s

大概就是0.3ms结束运行。

输入输出音频对比:

 如果不进行归一化,运行时间会减少很多。代码修改:

void voice_frame(short *x, int Nframes, short *xout, int blk_index)
{
	int i, /*j,*/ k, n;

//	printf("blk_index:%d, Nframes:%d\n\n", blk_index, Nframes);

	if(blk_index==0)
	{
		//printf("the first block, do somthing init\n");
		//
	}

	//=========================    Start Processing   ===============================
	for(n=0, k=0; n<Nframes; n++) {
		/*input*/
		for(i=0; i<FRAME_LEN; i++) {
			one_in_dat[i]=x[k+i]*win[i];
			//one_in_dat[i]=(x[k+i]/32768.0)*win[i];
			//one_in_dat[i]=(x[k+i]/32768.0);
			//one_in_dat[i]=x[k+i];
		}

		/*process*/
		memset(one_in_dat_i, 0, FRAME_LEN);
		baselib_fft(one_in_dat, one_in_dat_i, 1, FRAME_LEN);
		baselib_fft(one_in_dat, one_in_dat_i, -1, FRAME_LEN);
		for(i=0; i<FRAME_LEN; i++)
			res_dat[i]=one_in_dat[i]/win[i];

		/*output*/
		if(n==Nframes-1) {
			for(i=0; i<FRAME_LEN; i++){
				xout[k+i]=(short)res_dat[i];
				//xout[k+i]=(short)(res_dat[i]*32768.0);
				//xout[k+i]=res_dat[i];
			}
			return;
		}

		for(i=0; i<STEP_LEN; i++){
			one_out_dat[i]=res_dat[i];
		}

		for(i=0; i<STEP_LEN; i++){
			xout[k+i]=(short)res_dat[i];
			//xout[k+i]=(short)(one_out_dat[i]*32768.0);
			//xout[k+i]=one_out_dat[i];
		}

		//update step
		k=k+STEP_LEN;
	}

}

运行结果:

inputdata_length:81920

count:81920

in_dat_len:2048

all_block:20

a block can div to Nframes:15

time=0.0002430000s

time=0.0002390000s

time=0.0002380000s

time=0.0002380000s

time=0.0002380000s

time=0.0002380000s

time=0.0002660000s

time=0.0002620000s

time=0.0002380000s

time=0.0002380000s

time=0.0002380000s

time=0.0002380000s

time=0.0002380000s

time=0.0002380000s

time=0.0002390000s

time=0.0002380000s

time=0.0002570000s

time=0.0002390000s

time=0.0002380000s

time=0.0002380000s

大概就是0.2ms结束运行。有了统计运行时间的手段,就可以对算法进行时间上以及空间上的优化。

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

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

相关文章

kotlin 编写一个简单的天气预报app(二)

增加界面显示openweathermap返回的信息。 在activity_main.xml里增加输入框来输入城市&#xff0c;在输入款旁边增加搜索按钮来进行查询。 然后原来显示helloworld的TextView用来显示结果。 1. 增加输入城市名字的EditText <EditTextandroid:id"id/editTextCity"…

AcrelEMS企业微电网能效管理平台实现用户侧智能配电和智能用电管理-安科瑞黄安南

摘要&#xff1a;随着科技的发展&#xff0c;电力系统正逐步向智能化、数字化、互联网化迈进。智能配电与智能用电是电力产业发展的重要方向&#xff0c;将为传统电力系统带来革命性的变革。本文将对智能配电和智能用电的概念、特点、关键技术及应用进行详细介绍。 1、智能配电…

Rust vs Go:常用语法对比(八)

题目来自 Golang vs. Rust: Which Programming Language To Choose in 2023?[1] 141. Iterate in sequence over two lists Iterate in sequence over the elements of the list items1 then items2. For each iteration print the element. 依次迭代两个列表 依次迭代列表项1…

【linux基础(一)】Linux基本指令(上)

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:Linux从入门到开通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学更多操作系统知识   &#x1f51d;&#x1f51d; 这里写目录标题 1. 前言1. 创…

[vulnhub]DC2

文章目录 [vulnhub]DC2信息收集flag1flag2cewlwpscan flag3什么是rbash&#xff1f; flag4flag5git提权 总结 [vulnhub]DC2 信息收集 扫ip&#xff0c;有两种方式&#xff1a;arp、nmap nmap -sP 192.168.56.0/24 -T4arp-scan -l192.168.56.137 扫端口&#xff1a; nmap -…

1312. 让字符串成为回文串的最少插入次数;971. 翻转二叉树以匹配先序遍历

1312. 让字符串成为回文串的最少插入次数 核心思想&#xff1a;最后的回文串有两种情况&#xff0c;一种是奇数回文串&#xff0c;一种是偶数回文串&#xff0c;奇数回文串的中心一定是原来就有的&#xff0c;偶数回文串的中心也是原来就有的。假设除去中心的部分为q,p,最后要…

Debian12中为python3配置虚拟环境及在Pycharm中使用虚拟环境

在Debian 12中&#xff0c;python默认为python 3.11。 基于应用&#xff0c;现需设置虚拟环境。 1.安装venv模块 从python3.3开始&#xff0c;配置python虚拟环境&#xff0c;可用venv模块&#xff0c;更加方便了。 执行命令&#xff1a; #apt install python3.11-venv 2.…

原型模式——对象的克隆

1、简介 1.1、概述 可以通过一个原型对象克隆出多个一模一样的对象&#xff0c;该模式被称为原型模式。 在使用原型模式时&#xff0c;需要首先创建一个原型对象&#xff0c;再通过复制这个原型对象来创建更多同类型的对象。 1.2、定义 原型模式&#xff08;Prototype Patt…

ICASSP 2023说话人识别方向论文合集(一)

ICASSP (International Conference on Acoustics, Speech and Signal Processing) 即国际声学、语音与信号处理会议&#xff0c;是IEEE主办的全世界最大、最全面的信号处理及其应用方面的顶级会议&#xff0c;在国际上享有盛誉并具有广泛的学术影响力。 今年入选 ICASSP 2023 …

【LeetCode每日一题】——946.验证栈序列

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时间频度】九【代码实现】十【提交结果】 一【题目类别】 栈 二【题目难度】 中等 三【题目编号】 946.验证栈序列 四【题目描述】 给定 pushed 和 p…

【*1900 图论】CF1328 E

Problem - E - Codeforces 题意&#xff1a; 思路&#xff1a; 注意到题目的性质&#xff1a;满足条件的路径个数是极少的&#xff0c;因为每个点离路径的距离<1 先考虑一条链&#xff0c;那么直接就选最深那个点作为端点即可 为什么&#xff0c;因为我们需要遍历所有点…

ChatGPT伦理挑战:人工智能的权利与责任

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

选读SQL经典实例笔记13_case与聚合

1. 识别非小计行 1.1. 结果集 1.2. DB2 1.3. Oracle 1.4. 超级聚合&#xff08;supera ggregate&#xff09;值 1.4.1. sql select deptno, job, sum(sal) sal,grouping(deptno) deptno_subtotals,grouping(job) job_subtotalsfrom empgroup by cube(deptno,job) 1.5. SQ…

十三、数据结构——二叉树的遍历(先序、中序和后序)详细思路和代码

二叉树遍历 在数据结构中&#xff0c;二叉树是一种常用且重要的数据结构。二叉树的遍历是指按照一定顺序访问二叉树的所有节点&#xff0c;常见的遍历方式有前序遍历、中序遍历和后序遍历。本文将详细介绍这三种遍历算法&#xff0c;并介绍最优二叉树。 二叉树的基本定义 首…

网络摄像机·监控摄像机用镜头驱动芯片(内置光圈控制)MS41908M

产品简述 MS41908M 是一款用于网络摄像机和监控摄像机的镜头 驱动芯片。 芯片内置光圈控制功能&#xff1b;通过电压驱动方式以及扭矩纹 波修正技术&#xff0c;实现了超低噪声微步驱动。 主要特点  电压驱动方式&#xff0c;256 微步驱动电路&#xff08;两通道&…

同一份数据,Redis为什么要存两次

Redis作为目前最主流的高性能缓存&#xff0c;里面有很多精妙的设计&#xff0c;其中有一种数据类型&#xff0c;当在存储的时候会同时采用两种数据结构来进行分别存储&#xff0c;那么 Redis 为什么要这么做呢&#xff1f;这么做会造成同一份数据占用两倍空间吗&#xff1f; …

Python中的元类MetaClass

引言 python中的元类MetaClass&#xff1a;本质也是一个类&#xff0c;但和普通类的用法不同&#xff0c;它可以对类内部的定义&#xff08;包括类属性和类方法&#xff09;进行动态的修改。 换句话说&#xff0c;使用元类的主要目的是为了实现在创建类时&#xff0c;能够动态…

数据库架构设计

数据库架构设计 数据库架构分类 介绍 介绍常见的 四种 数据库架构设计模型&#xff1a; 单库架构、分组架构、分片架构和分组分片架构 &#xff0c;以及每种架构的 使用场景、存在的问题和对应的解决方案 。 一、数据模型 我们以 “ 用户中心 ” 数据库作为 数据模型 &…

python核心-面向对象-方法相关-补充

class Person:__age 18def __run(self):print("pao")def _Person__run(self):print("xxx")p Person # p._Person__run()print(Person.__dict__) 内置特殊方法 信息格式化操作 # class Person: # def __init__(self, n, a): # self.name n …

深入理解Linux 内核追踪机制

Linux 存在众多 tracing tools&#xff0c;比如 ftrace、perf&#xff0c;他们可用于内核的调试、提高内核的可观测性。众多的工具也意味着繁杂的概念&#xff0c;诸如 tracepoint、trace events、kprobe、eBPF 等&#xff0c;甚至让人搞不清楚他们到底是干什么的。本文尝试理清…