println 停止线程

您上一次尝试学习一种新的编程语言是什么时候? 您是否坚持尝试和真实,还是在新产品发布后立即尝试的勇敢灵魂之一? 无论哪种方式,学习一种新语言都是非常有用的,而且很有趣。

您可以尝试一个简单的“世界,您好!” 然后继续编写一些示例代码并执行它,在此过程中进行较小的更改,然后从那里继续进行。 无论我们使用哪种技术,我都相信我们都经历了这段经历。 虽然如果您确实设法坚持使用某种语言,并且希望精通该语言,则有一些方法可以帮助您。

其中之一是调试器。 有些人更喜欢在代码中使用简单的“打印”语句进行调试,并且对于一些简单的行程序也很好。 但是,如果您在一个有多个开发人员和数千行代码的大型项目中工作,那么投资调试器是有意义的。

我最近开始学习Go编程语言,在本文中,我们将探索一个名为Delve的调试器。 Delve是用于调试Go程序的特殊实用程序,我们将使用一些示例Go代码来介绍其某些功能。 不用担心这里提供的Go代码示例; 即使您以前从未在Go中进行编程,它们也是可以理解的。 Go的目标之一是简单,因此代码是一致的,这可以更容易理解和解释。

Delve简介

GitHub的

用自己的话说:

Delve是Go编程语言的调试器。 该项目的目标是为Go提供一个简单的,功能齐全的调试工具。 Delve应该易于调用和易于使用。 如果您使用的是调试器,那么事情就不会顺其自然。 考虑到这一点,Delve应该尽可能远离您。

让我们仔细看看。

我的测试系统是一台运行Fedora Linux以及以下Go编译器版本的笔记本电脑:

$ cat / etc / fedora - release
Fedora release 30 ( Thirty )
$
$ go version
go version go1 . 12 . 17 linux / amd64
$

Golang安装

如果您尚未安装Go,则可以通过简单地运行以下命令从已配置的存储库中获取它来获取它。

 $ dnf install golang . x86_64 

或者,您可以访问安装页面以获取适合您的操作系统发行版的其他安装选项。

在开始之前,请确保按照Go工具的要求设置了以下必需的PATHS。 如果未设置这些路径,则某些示例可能不起作用。 这些可以在SHELL的RC文件中轻松设置为环境变量,例如我的$HOME/bashrc文件。

$ go env | grep GOPATH
GOPATH = "/home/user/go"
$
$ go env | grep GOBIN
GOBIN = "/home/user/go/gobin"
$

进行安装

您可以通过运行一个简单的go get命令来安装Delve,如下所示。 go get是从外部源下载和安装所需软件包的Golang方法。 如果确实遇到安装问题,请在此处参考Delve的安装说明。

$ go get - u github . com / go - delve / delve / cmd / dlv
$

运行上面的命令会将Delve下载到$ GOPATH位置,在默认情况下,该位置恰好是$ HOME / go。 如果将$ GOPATH设置为其他值,则将有所不同。

您可以转到go /目录,在bin /目录下将看到dlv 。

$ ls - l $HOME / go
total 8
drwxrwxr - x . 2 user user 4096 May 25 19 : 11 bin
drwxrwxr - x . 4 user user 4096 May 25 19 : 21 src
$
$ ls - l ~ / go / bin /
total 19596
- rwxrwxr - x . 1 user user 20062654 May 25 19 : 17 dlv
$

由于Delve是在$ GOPATH下安装的,因此它也可以作为常规的shell命令使用,因此您不必每次都移至其安装目录。 您可以通过使用version选项运行dlv来验证dlv是否已正确安装。 它安装的版本是1.4.1。

$ which dlv
~ / go / bin / dlv
$
$ dlv version
Delve Debugger
Version : 1 . 4 . 1
Build : $Id : bda606147ff48b58bde39e20b9e11378eaa4db46 $
$

现在,让我们将Delve与一些Go程序一起使用以了解其功能以及如何使用它们。 在处理所有程序时,让我们从一个简单的“ Hello,world!”开始。 消息,在Go中称为hello.go 。

记住,我将这些示例程序放在$ GOBIN目录中。

$ pwd
/ home / user / go / gobin
$
$ cat hello . go
package main

import "fmt"

func main () {
fmt . Println ( "Hello, world!" )
}
$


要构建Go程序,请运行build命令并使用.go扩展名将其与源文件一起提供。 如果程序没有任何语法问题,则Go编译器会对其进行编译并输出二进制文件或可执行文件。 然后可以直接执行此文件,我们将看到“您好,世界!” 屏幕上显示的消息。

$ go build hello . go
$
$ ls - l hello
- rwxrwxr - x . 1 user user 1997284 May 26 12 : 13 hello
$
$ ./ hello
Hello , world !
$

在Delve中加载程序

有两种方法可以将程序加载到Delve调试器中。

当源代码尚未编译为二进制时,请使用debug参数。

第一种方法是仅在需要源文件时使用debug命令。 Delve为您编译一个名为__debug_bin的二进制文件,并将其加载到调试器中。

在此示例中,移至hello.go所在的目录,然后运行dlv debug命令。 如果目录中有多个Go源文件,并且每个源文件都有自己的主要功能,则Delve可能会引发错误,期望使用单个程序或单个项目来构建二进制文件。 如果发生这种情况,最好使用下面显示的第二个选项。

$ ls -l
total 4
-rw-rw-r--. 1 user user 74 Jun  4 11 : 48 hello.go
$
$ dlv debug
Type 'help' for list of commands.
( dlv )


现在打开另一个终端并列出同一目录的内容。 您会看到一个附加的__debug_bin二进制文件,该二进制文件是从源代码编译并加载到调试器中的。 现在,您可以移至dlv提示符,以继续使用Delve。

$ ls -l
total 2036
-rwxrwxr-x. 1 user user 2077085 Jun  4 11 : 48 __debug_bin
-rw-rw-r--. 1 user user      74 Jun  4 11 : 48 hello.go
$


使用exec参数
将程序加载到Delve中的第二种方法在您具有预编译的Go二进制文件或已经使用go build命令进行了编译并且不希望Delve将其编译为`__debug_bin`二进制文件时很有用。 在这种情况下,请使用exec参数将二进制目录加载到Delve调试器中。

$ ls -l
total 4
-rw-rw-r--. 1 user user 74 Jun  4 11 : 48 hello.go
$
$ go build hello.go
$
$ ls -l
total 1956
-rwxrwxr-x. 1 user user 1997284 Jun  4 11 : 54 hello
-rw-rw-r--. 1 user user      74 Jun  4 11 : 48 hello.go
$
$ dlv exec . / hello
Type 'help' for list of commands.
( dlv )

在Delve中获得帮助

dlv提示符下,您可以运行help以查看Delve中可用的各种帮助选项。 命令列表非常广泛,我们将在此处介绍一些重要功能。 以下是Delve功能的概述。

( dlv ) help
The following commands are available :

Running the program :

Manipulating breakpoints :

Viewing program variables and memory :

Listing and switching between threads and goroutines :

Viewing the call stack and selecting frames :

Other commands :

Type help followed by a command for full documentation .
( dlv )


设置断点

现在,我们已经在Delve调试器中加载了hello.go程序,让我们在主函数上设置断点,然后进行确认。 在Go中,主程序以main.main ,因此您需要将此名称提供给break command 。 接下来,我们将查看是否使用breakpoints命令正确设置了breakpoints

另外,请记住,您可以使用命令的简写形式,因此break main.main使用break main.main ,还可以使用b main.main来达到相同的效果,或者使用bp代替breakpoints 。 要查找命令的确切速记,请通过运行help命令来参考帮助部分。

( dlv ) break main . main
Breakpoint 1 set at 0x4a228f for main . main () ./ hello . go : 5
( dlv ) breakpoints
Breakpoint runtime - fatal - throw at 0x42c410 for runtime . fatalthrow () / usr / lib / golang / src / runtime / panic . go : 663 ( 0 )
Breakpoint unrecovered - panic at 0x42c480 for runtime . fatalpanic () / usr / lib / golang / src / runtime / panic . go : 690 ( 0 )
print runtime . curg . _panic . arg
Breakpoint 1 at 0x4a228f for main . main () ./ hello . go : 5 ( 0 )
( dlv )

继续执行程序

现在,让我们继续使用“继续”运行程序。 它会一直运行到到达断点为止,在本例中,该断点是main.main或main函数。 从那里,我们可以使用next一条命令逐行执行程序。 请注意,一旦移至fmt.Println("Hello, world!") ,我们就可以看到Hello, world! 当我们仍在调试器会话中时,将打印到屏幕上。

( dlv ) continue
> main . main () ./ hello . go : 5 ( hits goroutine ( 1 ): 1 total : 1 ) ( PC : 0x4a228f )
1 : package main
2 :
3 : import "fmt"
4 :
= >   5 :      func main () {
6 :         fmt . Println ( "Hello, world!" )
7 : }
( dlv ) next
> main . main () ./ hello . go : 6 ( PC : 0x4a229d )
1 : package main
2 :
3 : import "fmt"
4 :
5 : func main () {
= >   6 :              fmt . Println ( "Hello, world!" )
7 : }
( dlv ) next
Hello , world !
> main . main () ./ hello . go : 7 ( PC : 0x4a22ff )
2 :
3 : import "fmt"
4 :
5 : func main () {
6 :         fmt . Println ( "Hello, world!" )
= >   7 :      }
( dlv )

退出Delve

如果您希望随时退出调试器,则可以运行quit命令,您将返回到shell提示符。 很简单,对吧?

( dlv ) quit
$

让我们使用其他一些Go程序来探索其他Delve功能。 这次,我们将从Golang旅游中挑选一个节目。 如果您正在学习Go,那么Golang游览应该是您的第一站。

以下程序functions.go只是显示了如何在Go程序中定义和调用函数。 在这里,我们有一个简单的add()函数,该函数将两个数字相加并返回它们的值。 您可以构建程序并执行它,如下所示。

$ cat functions . go
package main

import "fmt"

func add ( x int , y int ) int {
return x + y
}

func main () {
fmt . Println ( add ( 42 , 13 ))
}
$


您可以构建程序并执行,如下所示。

$ go build functions . go  && ./ functions
55
$

踏入功能

如前所述,让我们使用前面提到的选项之一将二进制文件加载到Delve调试器中,再次在main.main设置一个断点,并在main.main断点时继续运行程序。 然后点击next直到到达fmt.Println(add(42, 13)) ; 在这里,我们调用add()函数。 我们可以使用Delve step命令从main函数移至add()函数,如下所示。

$ dlv debug
Type 'help' for list of commands .
( dlv ) break main . main
Breakpoint 1 set at 0x4a22b3 for main . main () ./ functions . go : 9
( dlv ) c
> main . main () ./ functions . go : 9 ( hits goroutine ( 1 ): 1 total : 1 ) ( PC : 0x4a22b3 )
4 :
5 : func add ( x int , y int ) int {
6 :         return x + y
7 : }
8 :
= >   9 :      func main () {
10 :         fmt . Println ( add ( 42 , 13 ))
11 : }
( dlv ) next
> main . main () ./ functions . go : 10 ( PC : 0x4a22c1 )
5 : func add ( x int , y int ) int {
6 :         return x + y
7 : }
8 :
9 : func main () {
= >  10 :              fmt . Println ( add ( 42 , 13 ))
11 : }
( dlv ) step
> main . add () ./ functions . go : 5 ( PC : 0x4a2280 )
1 : package main
2 :
3 : import "fmt"
4 :
= >   5 :      func add ( x int , y int ) int {
6 :         return x + y
7 : }
8 :
9 : func main () {
10 :         fmt . Println ( add ( 42 , 13 ))
( dlv )

使用文件名设置断点:linenumber

上面,我们经历了main ,然后移到add()函数,但是您也可以使用filename:linenumber组合直接在需要的地方设置断点。 以下是在add()函数开始时设置断点的另一种方法。

( dlv ) break functions . go : 5
Breakpoint 1 set at 0x4a2280 for main . add () ./ functions . go : 5
( dlv ) continue
> main . add () ./ functions . go : 5 ( hits goroutine ( 1 ): 1 total : 1 ) ( PC : 0x4a2280 )
1 : package main
2 :
3 : import "fmt"
4 :
= >   5 :      func add ( x int , y int ) int {
6 :         return x + y
7 : }
8 :
9 : func main () {
10 :         fmt . Println ( add ( 42 , 13 ))
( dlv )

查看当前堆栈详细信息

现在我们已经在add()函数上了,我们可以使用Delve中的stack命令查看堆栈的当前内容。 这显示了最上面的函数add()在0处,其次是main.main在1从那里调用add()函数。 main.main下面的main.main属于Go运行时,该运行时负责加载和执行程序。

( dlv ) stack
0  0x00000000004a2280 in main . add
at ./ functions . go : 5
1  0x00000000004a22d7 in main . main
at ./ functions . go : 10
2  0x000000000042dd1f in runtime . main
at / usr / lib / golang / src / runtime / proc . go : 200
3  0x0000000000458171 in runtime . goexit
at / usr / lib / golang / src / runtime / asm_amd64 . s : 1337
( dlv )

在框架之间移动

使用Delve中的frame命令,我们可以随意在上述帧之间切换。 在下面的示例中,使用frame 1将我们从add()框架内切换到main.main框架,依此类推。

( dlv ) frame 0
> main . add () ./ functions . go : 5 ( hits goroutine ( 1 ): 1 total : 1 ) ( PC : 0x4a2280 )
Frame 0 : ./ functions . go : 5 ( PC : 4a2280 )
1 : package main
2 :
3 : import "fmt"
4 :
= >   5 :      func add ( x int , y int ) int {
6 :         return x + y
7 : }
8 :
9 : func main () {
10 :         fmt . Println ( add ( 42 , 13 ))
( dlv ) frame 1
> main . add () ./ functions . go : 5 ( hits goroutine ( 1 ): 1 total : 1 ) ( PC : 0x4a2280 )
Frame 1 : ./ functions . go : 10 ( PC : 4a22d7 )
5 : func add ( x int , y int ) int {
6 :         return x + y
7 : }
8 :
9 : func main () {
= >  10 :              fmt . Println ( add ( 42 , 13 ))
11 : }
( dlv )

打印功能参数

函数通常接受多个参数进行处理。 对于add()函数,它接受两个整数。 Delve有一个方便的命令args ,它显示传递给该函数的命令行参数。

( dlv ) args
x = 42
y = 13
~r2 = 824633786832
( dlv )

查看拆卸

由于我们正在处理编译的二进制文件,因此能够查看由编译器生成的汇编语言指令非常有帮助。 Delve提供了一个disassemble命令来查看这些内容。 在下面的示例中,我们使用它来查看add()函数的反汇编指令。

( dlv ) step
> main . add () ./ functions . go : 5 ( PC : 0x4a2280 )
1 : package main
2 :
3 : import "fmt"
4 :
= >   5 :      func add ( x int , y int ) int {
6 :         return x + y
7 : }
8 :
9 : func main () {
10 :         fmt . Println ( add ( 42 , 13 ))
( dlv ) disassemble
TEXT main . add ( SB ) / home / user / go / gobin / functions . go
= >   functions . go : 5  0x4a2280   48c744241800000000   mov qword ptr [ rsp + 0x18 ], 0x0
functions . go : 6  0x4a2289   488b442408           mov rax , qword ptr [ rsp + 0x8 ]
functions . go : 6  0x4a228e   4803442410           add rax , qword ptr [ rsp + 0x10 ]
functions . go : 6  0x4a2293   4889442418           mov qword ptr [ rsp + 0x18 ], rax
functions . go : 6  0x4a2298   c3                   ret
( dlv )

功能升级

另一个功能是stepout ,它使我们能够返回到调用该函数的位置。 在我们的例子,如果我们希望回到main.main功能,我们可以简单地运行stepout命令,它会带我们回去。 这可能是一个非常方便的工具,可以帮助您在大型代码库中移动。

( dlv ) stepout
> main . main () ./ functions . go : 10 ( PC : 0x4a22d7 )
Values returned :
~r2 : 55

5 : func add ( x int , y int ) int {
6 :         return x + y
7 : }
8 :
9 : func main () {
= >  10 :              fmt . Println ( add ( 42 , 13 ))
11 : }
( dlv )


让我们使用Go导览中的另一个示例程序来了解Delve如何处理Go中的变量。 下面的示例程序定义并初始化了一些不同类型的变量。 您可以构建程序并执行它。

$ cat variables . go
package main

import "fmt"

var i , j int = 1 , 2

func main () {
var c , python , java = true , false , "no!"
fmt . Println ( i , j , c , python , java )
}
$

$ go build variables . go && ./ variables
1 2 true false no !
$


打印变量信息

如前所述,使用delve debug将程序加载到调试器中。 您可以在Delve中使用print命令以及变量名来显示其当前值。

( dlv ) print c
true
( dlv ) print java
"no!"
( dlv )

另外,您可以使用locals命令来打印函数中的所有局部变量。

( dlv ) locals
python = false
c = true
java = "no!"
( dlv )

如果您不知道变量的类型,则可以将whatis命令与变量名一起使用以打印类型。

( dlv ) whatis python
bool
( dlv ) whatis c
bool
( dlv ) whatis java
string
( dlv )

结论

到目前为止,我们仅涉及了Delve提供的功能。 您可以参考help部分并尝试其他各种命令。 其他一些有用的功能包括将Delve附加到正在运行的Go程序(守护程序!),甚至在安装了Go源代码包的情况下,甚至使用Delve来探索Golang库的某些内部组件。 继续探索!

翻译自: https://opensource.com/article/20/6/debug-go-delve

println 停止线程

println 停止线程_停止调试使用Println并改用Delve相关推荐

  1. pyqt stop停止线程_面试官:如何终止线程?有几种方式?

    在 Java 中有以下 3 种方法可以终止正在运行的线程: 使用退出标志,使线程正常退出,也就是当 run() 方法完成后线程终止: 使用 stop() 方法强行终止线程,但是不推荐使用这个方法,因为 ...

  2. pyqt stop停止线程_面试阿里,字节跳动,腾讯90%都会被问到如何终止线程?有几种方式?你都知道吗?...

    在 Java 中有以下 3 种方法可以终止正在运行的线程: 使用退出标志,使线程正常退出,也就是当 run() 方法完成后线程终止: 使用 stop() 方法强行终止线程,但是不推荐使用这个方法,因为 ...

  3. pthread 立即停止线程_线程取消(pthread_cancel)

    基本概念 pthread_cancel调用并不等待线程终止,它只提出请求.线程在取消请求(pthread_cancel)发出后会继续运行, 直到到达某个取消点(CancellationPoint).取 ...

  4. 软件测试 测试停止标准_停止正常测试

    软件测试 测试停止标准 I see a lot of data scientists using tests such as the Shapiro-Wilk test and the Kolmogo ...

  5. 数据停止命令_停止提供您的数据

    数据停止命令 背景 (The Background) Today's installment is all about the traps - usually hiding in plain sigh ...

  6. celery 停止任务_停止/清除Django-Celery中的定期任务

    任务是一条消息,"周期性任务"定期发送任务消息.每个发送的任务都会分配一个唯一的ID. revoke将只取消单个任务消息.要获取任务的ID,您必须保留发送ID的 跟踪,但您也可以在 ...

  7. 【Java 语言】Java 多线程 一 ( 线程基础 : 线程启动 | 线程停止 | 线程暂停 | 线程优先级 | 守护线程)

    一. 线程启动 线程启动 : -- 1. 继承 Thread 运行线程 : 重写 Thread 类的 run 方法, 然后执行该线程; -- 2. 实现 Runnable 接口, 并运行线程; -- ...

  8. 测试停止线程(Java)

    测试停止线程(Java) 1.建议线程正常停止->利用次数,不建议死循环 2.建议使用标志位->设置一个标志 3.不要使用stop或者destroy等过时或者JDK不建议使用的方法 pac ...

  9. java以正确的方式停止线程

    java线程停止可以说是非常有讲究的,看起来非常简单,但是也要做好一些防范措施,一般停止一个线程可以使用Thread.stop();来实现,但是最好不要用,因为他是不安全的. 大多数停止线程使用Thr ...

最新文章

  1. 2017年计算机四级试题,2017年全国计算机四级考试模拟试题与答案
  2. 在 Android 开发中使用 Kotlin 协程 (一) -- 初识 Kotlin 协程
  3. 阻塞队列和ArrayBlockingQueue源码解析
  4. 荣耀V40值得购买吗?玩游戏是一把好手!
  5. mysql fetch rows,php中mysql_fetch_array()和mysql_fetch_rows()函数区别
  6. 【渝粤教育】电大中专测量学 (5)作业 题库
  7. Java比较器概述即代码讲解实现
  8. NRF52840 BLE OTA
  9. 昂达平板不能开机刷机_昂达平板电脑怎么刷机?昂达平板电脑刷机教程
  10. html+css美化后台登录界面
  11. 微信内置浏览器不能下载应用文件的解决方案-微信跳转手机默认浏览器
  12. 「开发者说」钉钉连接器+OA审批实现学校学生假勤场景数字化
  13. 我的人生观、爱情观和世界观
  14. c语言自我介绍范文,个性的自我介绍范文5篇
  15. @ds实现多数据源切换及解决事务失效问题
  16. 时间晶体,一种曾被认为是无法存在的物质,被创造出来了吗?
  17. 色彩原理:三原色、色彩三要素、色彩模型
  18. android监控摄像头,监控其实很简单 给摄像头装个安卓系统
  19. python快速爬虫视频_“python怎么快速爬虫视频“python 爬网页视频教程
  20. redis内存占用过高的问题排查

热门文章

  1. 2017年度IT168技术卓越奖名单:服务器类
  2. js中用script 嵌套script块
  3. 完整部署CentOS7.2+OpenStack+kvm 云平台环境(3)--为虚拟机指定固定ip
  4. maven-resources-plugin插件使用
  5. POJ2942 Knights of the Round Table 点双连通分量,逆图,奇圈
  6. 创建动态链接库时设置导出函数的方法
  7. 修改am335x 制作android sd启动卡的bug
  8. 好用又被遗忘的Char,String 方法
  9. Linux的文件权限与目录设置
  10. github代码的提交与下载