Golang-语言源码级调试器 Delve

news2025/2/23 11:12:09

在这里插入图片描述

前言

Go 目前的调试器有如下几种:

  • GDB 最早期的调试工具,现在用的很少。
  • LLDB macOS 系统推荐的标准调试工具,单 Go 的一些专有特性支持的比较少。
  • Delve 专门为 Go 语言打造的调试工具,使用最为广泛。

本篇简单说明如何使用 Delve 工具来调试 Go 程序,使用的 delve 版本为 1.20.1。

delve 的汉语意思是:钻研、探索;用这个来命名一个debug工具还是非常的形象。

安装

已知以下说明适用于 Linux、macOS、Windows 和 FreeBSD。

克隆 git 存储库并构建:

$ git clone https://github.com/go-delve/delve
$ cd delve
$ go install github.com/go-delve/delve/cmd/dlv

或者,在 Go 版本 1.16 或更高版本上:

Install the latest release:
$ go install github.com/go-delve/delve/cmd/dlv@latest

Install at tree head:
$ go install github.com/go-delve/delve/cmd/dlv@master

安装在一个特定的版本或:

$ go install github.com/go-delve/delve/cmd/dlv@v1.7.3
$ go install github.com/go-delve/delve/cmd/dlv@v1.7.4-0.20211208103735-2f13672765fe

命令

Usage:
  dlv [command]

Available Commands:
  attach      附加到正在运行的进程并开始调试.
  connect     使用终端客户端连接到无头调试服务器.
  core        检查核心转储.
  dap         启动一个通过调试适配器协议(DAP)通信的无头TCP服务器.
  debug       编译并开始调试当前目录中的主包或指定的包.
  exec        执行预编译的二进制文件,并开始调试会话.
  help        Help about any command
  run         弃用的命令。使用'debug'代替.
  test        编译测试二进制文件并开始调试程序.
  trace       编译并开始跟踪程序.
  version     Prints version.

[操作] 示例代码

下面是检查操作的代码

.test/
├── go.mod
├── main.go
└── main_test.go
module debug_sample

go 1.18

main.go 执行以下处理:

package main

import (
	"fmt"
)

var abc string

func init() {
	abc = "wakuwaku bank"
}

func add(a, b int) int {
	fmt.Printf("func add %v\n", abc)
	return a + b
}

func sub(a, b int) int {
	fmt.Printf("func sub %v\n", abc)
	return a - b
}

func calculate(a, b int) (addValue, subValue int) {
	addValue = add(a, b)
	subValue = sub(a, b)
	return addValue, subValue
}

func sampleFunc1() {
	for i := 0; i < 10; i++ {
		a := i + 10
		b := i
		addValue, subValue := calculate(a, b)
		fmt.Printf("addValue: %v subValue: %v\n", addValue, subValue)
	}
}

func main() {
	sampleFunc1()
}

main_test.go 执行以下处理:

package main

import "testing"

func Test_add(t *testing.T) {
	type args struct {
		a int
		b int
	}
	tests := []struct {
		name string
		args args
		want int
	}{{name: "Both positive values", args: args{10, 3}, want: 13}}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := add(tt.args.a, tt.args.b); got != tt.want {
				t.Errorf("add() = %v, want %v", got, tt.want)
			}
		})
	}
}

func Test_sub(t *testing.T) {
	type args struct {
		a int
		b int
	}
	tests := []struct {
		name string
		args args
		want int
	}{{name: "Both positive values", args: args{10, 3}, want: 7}}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := sub(tt.args.a, tt.args.b); got != tt.want {
				t.Errorf("sub() = %v, want %v", got, tt.want)
			}
		})
	}
}

[调试] dlv 调试

开始调试

$ dlv debug main.go
Type 'help' for list of commands.
(dlv) 

检查功能/代码( funcs list )

funcs main\..* 查看 main 文件 所有定义的方法

(dlv) funcs main\..*
main.add
main.calculate
main.init.0
main.main
main.sampleFunc1
main.sub
runtime.main.func1
runtime.main.func2

list 您可以在以下位置查看某个方法源代码

(dlv) list main.main
Showing /debug_sample/main.go:38 (PC: 0x1029dda10)
    33:                 addValue, subValue := calculate(a, b)
    34:                 fmt.Printf("addValue: %v subValue: %v\n", addValue, subValue)
    35:         }
    36: }
    37: 
    38: func main() {
    39:         sampleFunc1()
    40: }
(dlv) list main.sampleFunc1:3
Showing /debug_sample/main.go:32 (PC: 0x1029dd8c0)
    27: }
    28: 
    29: func sampleFunc1() {
    30:         for i := 0; i < 10; i++ {
    31:                 a := i + 10
    32:                 b := i
    33:                 addValue, subValue := calculate(a, b)
    34:                 fmt.Printf("addValue: %v subValue: %v\n", addValue, subValue)
    35:         }
    36: }
    37: 

设置/删除断点 ( break clear )

break 您可以使用以下命令设置断点

(dlv) break main.main
Breakpoint 1 set at 0x1029dda10 for main.main() ./main.go:38
(dlv) break main.sampleFunc1:3
Breakpoint 2 set at 0x1029dd8c0 for main.sampleFunc1() ./main.go:32

breakpoints 您可以检查中设置的断点。

(dlv) breakpoints
Breakpoint runtime-fatal-throw (enabled) at 0x10296c880 for runtime.throw() /Users/w/.gvm/gos/go1.18/src/runtime/panic.go:982 (0)
Breakpoint unrecovered-panic (enabled) at 0x10296cb90 for runtime.fatalpanic() /Users/w/.gvm/gos/go1.18/src/runtime/panic.go:1065 (0)
        print runtime.curg._panic.arg
Breakpoint 1 (enabled) at 0x1029dda10 for main.main() ./main.go:38 (0)
Breakpoint 2 (enabled) at 0x1029dd8c0 for main.sampleFunc1() ./main.go:32 (0)

clear 您可以使用 删除指定的断点。

(dlv) clear 1
Breakpoint 1 cleared at 0x1029dda10 for main.main() ./main.go:38
(dlv) breakpoints
Breakpoint runtime-fatal-throw (enabled) at 0x10296c880 for runtime.throw() /Users/w/.gvm/gos/go1.18/src/runtime/panic.go:982 (0)
Breakpoint unrecovered-panic (enabled) at 0x10296cb90 for runtime.fatalpanic() /Users/w/.gvm/gos/go1.18/src/runtime/panic.go:1065 (0)
        print runtime.curg._panic.arg
Breakpoint 2 (enabled) at 0x1029dd8c0 for main.sampleFunc1() ./main.go:32 (0)

clearall 删除所有断点。

(dlv) clearall
Breakpoint 1 cleared at 0x4986e6 for main.main() ./main.go:38
Breakpoint 5 cleared at 0x49858c for main.sampleFunc1() ./main.go:32

提前处理到断点( continue )

continue 让我们继续执行中设置的断点。

(dlv) continue
> main.sampleFunc1() ./main.go:32 (hits goroutine(1):1 total:1) (PC: 0x1029dd8c0)
    27: }
    28: 
    29: func sampleFunc1() {
    30:         for i := 0; i < 10; i++ {
    31:                 a := i + 10
=>  32:                 b := i
    33:                 addValue, subValue := calculate(a, b)
    34:                 fmt.Printf("addValue: %v subValue: %v\n", addValue, subValue)
    35:         }
    36: }
    37: 

continue 或者,您可以继续执行以下命令。

next
向前迈出一行(跨过)。
step
前进一行。
stepout
退出当前功能。

检查并覆盖变量 ( locals set )

[root@cdh2 test]# dlv debug main.go  // 调试
Type 'help' for list of commands.

(dlv) break main.sampleFunc1:3  // 设置断点
Breakpoint 1 set at 0x49858c for main.sampleFunc1() ./main.go:32

(dlv) c  // 跳到断点
> main.sampleFunc1() ./main.go:32 (hits goroutine(1):1 total:1) (PC: 0x49858c)
    27:	}
    28:
    29:	func sampleFunc1() {
    30:		for i := 0; i < 10; i++ {
    31:			a := i + 10
=>  32:			b := i
    33:			addValue, subValue := calculate(a, b)
    34:			fmt.Printf("addValue: %v subValue: %v\n", addValue, subValue)
    35:		}
    36:	}
    37:
    
(dlv) locals  // 打印局部变量
i = 0
a = 10

(dlv) vars main.abc
main.abc = "wakuwaku bank"

(dlv) print i
0
(dlv) print a
10

(dlv) set i = 2  // 重新给变量赋值
(dlv) print i
2

堆栈跟踪显示( stack frame )

首先,要检查操作,请继续添加功能。

(dlv) break main.add
Breakpoint 3 set at 0x1029dd610 for main.add() ./main.go:13
(dlv) c
> main.add() ./main.go:13 (hits goroutine(1):1 total:1) (PC: 0x1029dd610)
     8: 
     9: func init() {
    10:         abc = "wakuwaku bank"
    11: }
    12: 
=>  13: func add(a, b int) int {
    14:         fmt.Printf("func add %v\n", abc)
    15:         return a + b
    16: }
    17: 
    18: func sub(a, b int) int {

显示堆栈跟踪

(dlv) stack
0  0x00000000004982aa in main.add
   at ./main.go:13
1  0x00000000004984df in main.calculate
   at ./main.go:24
2  0x00000000004985a5 in main.sampleFunc1
   at ./main.go:33
3  0x00000000004986f7 in main.main
   at ./main.go:39
4  0x00000000004372d8 in runtime.main
   at /root/.go/src/runtime/proc.go:250
5  0x0000000000461661 in runtime.goexit
   at /root/.go/src/runtime/asm_amd64.s:1571

frame 您可以通过指定堆栈跟踪编号来检查代码和变量

(dlv) frame 2 ls
Goroutine 1 frame 2 at /debug_sample/main.go:33 (PC: 0x1029dd8d0)
    28: 
    29: func sampleFunc1() {
    30:         for i := 0; i < 10; i++ {
    31:                 a := i + 10
    32:                 b := i
=>  33:                 addValue, subValue := calculate(a, b)
    34:                 fmt.Printf("addValue: %v subValue: %v\n", addValue, subValue)
    35:         }
    36: }
    37: 
    38: func main() {
(dlv) frame 2 locals
i = 2
a = 10
b = 2

指定条件 ( condition )

首先,进行for语句的处理

$ dlv debug main.go
Type 'help' for list of commands.
(dlv) b main.sampleFunc1:3
Breakpoint 1 set at 0x1050958c0 for main.sampleFunc1() ./main.go:32
(dlv) c
> main.sampleFunc1() ./main.go:32 (hits goroutine(1):1 total:1) (PC: 0x1050958c0)
    27: }
    28: 
    29: func sampleFunc1() {
    30:         for i := 0; i < 10; i++ {
    31:                 a := i + 10
=>  32:                 b := i
    33:                 addValue, subValue := calculate(a, b)
    34:                 fmt.Printf("addValue: %v subValue: %v\n", addValue, subValue)
    35:         }
    36: }
    37: 
(dlv) locals
i = 0
a = 10

condition 您可以使用 设置断点条件。
i==5 让我们将其设置为停止时

(dlv) condition 1 i==5

(dlv) c
func add wakuwaku bank
func sub wakuwaku bank
addValue: 10 subValue: 10
func add wakuwaku bank
func sub wakuwaku bank
addValue: 12 subValue: 10
func add wakuwaku bank
func sub wakuwaku bank
addValue: 14 subValue: 10
func add wakuwaku bank
func sub wakuwaku bank
addValue: 16 subValue: 10
func add wakuwaku bank
func sub wakuwaku bank
addValue: 18 subValue: 10
> main.sampleFunc1() ./main.go:32 (hits goroutine(1):2 total:2) (PC: 0x1050958c0)
    27: }
    28: 
    29: func sampleFunc1() {
    30:         for i := 0; i < 10; i++ {
    31:                 a := i + 10
=>  32:                 b := i
    33:                 addValue, subValue := calculate(a, b)
    34:                 fmt.Printf("addValue: %v subValue: %v\n", addValue, subValue)
    35:         }
    36: }
    37: 
    
(dlv) locals
i = 5
a = 15

调试结束( exit )

exit 您可以使用 完成调试。

(dlv) exit

[debug] dlv测试(调试测试)

dlv test 您可以使用以下命令调试您的测试代码

$ dlv test
Type 'help' for list of commands.
(dlv) funcs test.Test*  // test.Test*  test 包含 Xxx_test.go 文件夹
debug_sample.Test_add
debug_sample.Test_add.func1
debug_sample.Test_sub
debug_sample.Test_sub.func1

(dlv) b test.Test_add
Breakpoint 1 set at 0x104891e90 for debug_sample.Test_add() ./main_test.go:5

(dlv) c
> debug_sample.Test_add() ./main_test.go:5 (hits goroutine(4):1 total:1) (PC: 0x104891e90)
     1: package main
     2: 
     3: import "testing"
     4: 
=>   5: func Test_add(t *testing.T) {
     6:         type args struct {
     7:                 a int
     8:                 b int
     9:         }
    10:         tests := []struct { 

[debug] dlv Attach(调试运行进程)

更正操作检查代码

对其进行修改以保持作为 Web 服务器运行,如下所示。

package main

import (
	"fmt"
	"net/http"
)

var abc string

func init() {
	abc = "wakuwaku bank"
}

func add(a, b int) int {
	fmt.Printf("func add %v\n", abc)
	return a + b
}

func sub(a, b int) int {
	fmt.Printf("func sub %v\n", abc)
	return a - b
}

func calculate(a, b int) (addValue, subValue int) {
	addValue = add(a, b)
	subValue = sub(a, b)
	return addValue, subValue
}

func sampleFunc1(w http.ResponseWriter, r *http.Request) {
	for i := 0; i < 10; i++ {
		a := i * 2
		b := i
		addValue, subValue := calculate(a, b)
		fmt.Fprintf(w, "addValue: %v subValue: %v\n", addValue, subValue)
	}
}

func main() {
	http.HandleFunc("/sample_func_1", sampleFunc1)
	http.ListenAndServe(":80", nil)
}

启动。

$ go build     
$ ./test

调试运行进程

检查进程 ID。

$ ps -ef | grep "test"
root     254882  56889  0 15:24 pts/2    00:00:00 ./test
root     257090  18100  0 15:25 pts/0    00:00:00 grep --color=auto test

调试

# dlv attach 254882
Type 'help' for list of commands.
(dlv)

设置断点并等待进程被调用。

(dlv) b main.sampleFunc1
Breakpoint 1 set at 0x1010e8470 for main.sampleFunc1() ./main.go:30

(dlv) c

尝试在另一个控制台中向端点发出请求。

$ curl http://localhost/sample_func_1

处理在设置的断点处停止,如下所示。

(dlv) c
> main.sampleFunc1() ./main.go:30 (hits goroutine(21):1 total:1) (PC: 0x1010e8470)
Warning: debugging optimized function
    25:         addValue = add(a, b)
    26:         subValue = sub(a, b)
    27:         return addValue, subValue
    28: }
    29: 
=>  30: func sampleFunc1(w http.ResponseWriter, r *http.Request) {
    31:         for i := 0; i < 10; i++ {
    32:                 a := i * 2
    33:                 b := i
    34:                 addValue, subValue := calculate(a, b)
    35:                 fmt.Fprintf(w, "addValue: %v subValue: %v\n", addValue, subValue)

命令说明

以下是一些最常用的命令。

断点相关

命令别名解释
breakb设置断点
breakpointsbp显示活动断点
clear删除断点
clearall删除所有断点
conditioncond设置断点条件

继续

命令别名解释
continuec继续到“下一个断点”或“程序结束”或“指定点”。(例如 c main.add:1 )
nextn向前迈出一行(跨过)。
steps前进一行。
stepoutso退出当前功能。
restart恢复该过程。
exitq退出调试器。

其他的

命令别名解释
funcs检查功能列表。(例如 funcs main…* )
listl显示代码。(例如 l 10 l main.main:3 )
locals检查局部变量。
vars检查包变量。
printp评估一个表达式。
set覆盖变量。
stackbt显示堆栈跟踪。

您还可以通过在调试过程中执行来查看如何使用其他命令 help

(dlv) help
The following commands are available:

Running the program:
    call ------------------------ Resumes process, injecting a function call (EXPERIMENTAL!!!)
    continue (alias: c) --------- Run until breakpoint or program termination.
    next (alias: n) ------------- Step over to next source line.
    rebuild --------------------- Rebuild the target executable and restarts it. It does not work if the executable was not built by delve.
    restart (alias: r) ---------- Restart process.
    step (alias: s) ------------- Single step through program.
    step-instruction (alias: si)  Single step a single cpu instruction.
    stepout (alias: so) --------- Step out of the current function.

Manipulating breakpoints:
    break (alias: b) ------- Sets a breakpoint.
    breakpoints (alias: bp)  Print out info for active breakpoints.
    clear ------------------ Deletes breakpoint.
    clearall --------------- Deletes multiple breakpoints.
    condition (alias: cond)  Set breakpoint condition.
    on --------------------- Executes a command when a breakpoint is hit.
    toggle ----------------- Toggles on or off a breakpoint.
    trace (alias: t) ------- Set tracepoint.
    watch ------------------ Set watchpoint.

Viewing program variables and memory:
    args ----------------- Print function arguments.
    display -------------- Print value of an expression every time the program stops.
    examinemem (alias: x)  Examine raw memory at the given address.
    locals --------------- Print local variables.
    print (alias: p) ----- Evaluate an expression.
    regs ----------------- Print contents of CPU registers.
    set ------------------ Changes the value of a variable.
    vars ----------------- Print package variables.
    whatis --------------- Prints type of an expression.

Listing and switching between threads and goroutines:
    goroutine (alias: gr) -- Shows or changes current goroutine
    goroutines (alias: grs)  List program goroutines.
    thread (alias: tr) ----- Switch to the specified thread.
    threads ---------------- Print out info for every traced thread.

Viewing the call stack and selecting frames:
    deferred --------- Executes command in the context of a deferred call.
    down ------------- Move the current frame down.
    frame ------------ Set the current frame, or execute command on a different frame.
    stack (alias: bt)  Print stack trace.
    up --------------- Move the current frame up.

Other commands:
    config --------------------- Changes configuration parameters.
    disassemble (alias: disass)  Disassembler.
    dump ----------------------- Creates a core dump from the current process state
    edit (alias: ed) ----------- Open where you are in $DELVE_EDITOR or $EDITOR
    exit (alias: quit | q) ----- Exit the debugger.
    funcs ---------------------- Print list of functions.
    help (alias: h) ------------ Prints the help message.
    libraries ------------------ List loaded dynamic libraries
    list (alias: ls | l) ------- Show source code.
    source --------------------- Executes a file containing a list of delve commands
    sources -------------------- Print list of source files.
    transcript ----------------- Appends command output to a file.
    types ---------------------- Print list of types

Type help followed by a command for full documentation.

参考

go-delve/delve:Delve 是 Go 编程语言的调试器

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

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

相关文章

printf %.*s 原来是这样

今天看代码时&#xff0c;看到这样一个printf&#xff0c;以前没见过这样的&#xff0c;也没这样用过&#xff0c;一下子还真不知道是什么意思&#xff1a; // Response is received. Print it struct mg_http_message *hm (struct mg_http_message *) ev_data; printf("…

今年的Prime Day2.0来了!亚马逊卖家爆单必做…

亚马逊的Prime Day已经成了全行业的零售假日&#xff0c;不仅仅是消费者离不开它&#xff0c;卖家也离不开这一年一度的狂欢销售盛宴。 回看刚刚过去的Prime Day大促&#xff0c;亚马逊在各方面都获得了较为不错的成绩。 根据亚马逊官方消息&#xff0c;在2023亚马逊Prime会员…

【网络】高级IO

目录 一、五种IO模型 1、阻塞IO 2、非阻塞IO 3、信号驱动 4、IO多路转接 5、异步IO 6、总结 二、高级IO重要概念 1、同步通信与异步通信 2、阻塞 vs 非阻塞 三、非阻塞IO 1、fcntl 2、实现函数SetNoBlock 四、IO多路转接select 1、select 1.1、参数解释 1.2、…

生信豆芽菜——配对型的复杂箱线图使用说明

网站&#xff1a;http://www.sxdyc.com/visualsBoxHalfPlot 一、配对型的复杂箱线图简介 配对型的复杂箱线图原理与箱线图相同&#xff0c;常见于配对样本的数据分析中&#xff0c;在日常研究中&#xff0c;我们会碰到配对资料&#xff0c;例如同一病人治疗前后的变化&#xff…

链表数组OJ题汇总

前言&#xff1a; 在计算机科学中&#xff0c;数组和链表是两种常见的数据结构&#xff0c;用于存储和组织数据。它们分别具有不同的特点和适用场景。 本博客将深入讨论数组和链表在OJ题目中的应用。我们将从基本概念开始&#xff0c;介绍数组和链表的定义和特点&#xff0c;并…

CSDN 我的资源在哪儿?资源上传后找不到?审核是否通过?

CSDN 我的资源在哪儿&#xff1f;资源上传后找不到&#xff1f;审核是否通过&#xff1f; 你是不是很奇怪&#xff0c;资源上传后&#xff0c;找不到了&#xff01;因为他在你们的数据里面不叫“资源”&#xff0c;而是叫“下载”。反正就是怪怪的。 在哪儿查找我的资源&…

力扣221.最大正方形(动态规划)

思路&#xff1a; 思路&#xff1a;从[0,0]元素开始&#xff0c;计算每个元素对应其与[0,0]之间矩阵块中最大正方形边长情况&#xff1a;1&#xff09;matrix [ i , j ] ‘0’ --> 元素对应的最大正方形为0。情况&#xff1a;2&#xff09;matrix [ i , j ] ‘1’ -->…

Java基础入门篇——修饰符

在Java中&#xff0c;修饰符&#xff08;Modifiers&#xff09;是一种用于修改类、方法、变量和其他实体的访问权限、行为或特性的关键字。Java提供了一组修饰符&#xff0c;可以用于实现对代码的封装、继承、多态和访问控制等功能。 1、访问修饰符&#xff08;Access Modifie…

如何将视频转换成音频mp3格式?试一下这几种转换方法

MP3格式是一种被广泛使用的音频格式&#xff0c;可以在几乎所有音频播放器和设备上播放。此外&#xff0c;由于视频文件通常包含大量图像信息&#xff0c;因此其文件大小通常比相应的音频文件要大得多。将视频转换为MP3格式音频可以大大减小文件大小&#xff0c;从而节省硬盘空…

Postman接口自动化测试实战,从0到1一篇彻底打通...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 postman中的测试 …

python办公自动化有用吗?,python办公自动化能干啥

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;python办公自动化有用吗?&#xff0c;python办公自动化电子书&#xff0c;现在让我们一起来看看吧&#xff01; 前 言 办公自动化是指利用现代化设备和技术&#xff0c;代替办公人员的部分手动或重复性业务活动&#x…

PYTHON专栏

PYTHON专栏 python基础教程 python基础教程 Python练手算法 Python练手算法 Python设计模式 Python设计模式 MySQL教程 MySQL教程 ORM框架SQLAlchemy Python ORM框架SQLAlchemy Python Web框架Django Python Web框架Django Web框架FastAPI Web框架FastAPI http库request…

Flutter系列文章-Flutter UI进阶

在本篇文章中&#xff0c;我们将深入学习 Flutter UI 的进阶技巧&#xff0c;涵盖了布局原理、动画实现、自定义绘图和效果、以及 Material 和 Cupertino 组件库的使用。通过实例演示&#xff0c;你将更加了解如何创建复杂、令人印象深刻的用户界面。 第一部分&#xff1a;深入…

三维模型OSGB格式轻量化压缩必要性分析

三维模型OSGB格式轻量化压缩必要性分析 三维模型是计算机图形学和视觉效果等领域的重要应用之一。然而&#xff0c;由于三维模型通常包含大量的几何信息、纹理信息和其他元素&#xff0c;导致其占用的存储空间和计算资源非常巨大。为了提高三维模型的处理效率和性能&#xff0…

C#实现邮箱验证码

开发环境&#xff1a;C#&#xff0c;VS2019&#xff0c;.NET Core 3.1&#xff0c;ASP.NET Core Web API&#xff0c;163邮箱 1、在163邮箱的设置中开通IMAP/SMTP的服务&#xff0c;授权成功后会弹出一个窗体&#xff08;如下图所示&#xff09;&#xff0c;上面显示了授权密码…

go重制版的海盗王gateserver网关服务端

海盗王原有的gateserver网关经常出现无故报错和掉地图的问题&#xff0c;经过反复修改都无法解决相关问题。 加上&#xff0c;原有的程序已经趋于古董级别&#xff0c;存在很大的兼容性问题。 以上&#xff0c;萌发了用go语言进行重新开发一个gateserver网关程序的想法&#xf…

科技巨头纷纷押注,Web3钱包能否成为撬动行业的支点?

出品&#xff5c;欧科云链研究院 作者&#xff5c;Hedy Bi 在PayPal推出稳定币并引发行业热议之际&#xff0c;公链Aptos昨日宣布与微软合作&#xff0c;共同探索与资产代币化、数字支付和中央银行数字货币相关的创新解决方案。尽管比尔盖茨对加密货币持摇摆态度&#xff0c;…

[小尘送书-第二期]《Power BI数据分析与可视化实战》数据清洗、数据建模、数据可视化设计与高级技法

大家好&#xff0c;我是小尘&#xff0c;欢迎你的关注&#xff01;大家可以一起交流学习&#xff01;欢迎大家在CSDN后台私信我&#xff01;一起讨论学习&#xff0c;讨论如何找到满意的工作&#xff01; &#x1f468;‍&#x1f4bb;博主主页&#xff1a;小尘要自信 &#x1…

F7--DDR4的读写测试-2023-08-11

1.场景 7系列的FPGA芯片不支持DDR4&#xff0c;使用DDR4需要更高性能的FPGA芯片&#xff0c;这里用到Kintex ultrascale是支持DDR4的&#xff0c;具体FPGA芯片是XCKU3P-2FFVA676I&#xff0c;DDR4的颗粒为MT40A512M16LY- 075E时钟频率为750MHz-1333MHz&#xff0c;单颗容量为1G…

JVM运行时五大数据区域详解

前言&#xff1a; java虚拟机再执行Java程序的时候把它所拥有的内存区域划分了若干个数据区域。这些区域有着不同的功能&#xff0c;各司其职。这些区域不但功能不同&#xff0c;创建、销毁时间也不同。有些区域为线程私有&#xff0c;如&#xff1a;每个线程都有自己的程序计数…