首页 > 其他分享 >Golang写时复制是否是原子性的?

Golang写时复制是否是原子性的?

时间:2022-11-14 16:35:42浏览次数:64  
标签:.. SP 是否是 Golang go MOVQ main gofile 写时


建议先阅读下Go汇编语言的入门教程
​​​ https://go.dev/doc/asm​

先说一下我这边的一个简化场景吧,有一个定时任务定时从数据库获取数据,也就是对应实例代码中的getNewProject(),获取完数据后,会直接赋给变量projectMap(projectMap其实就是作为一个缓存来用的);还会有程序从projectMap获取对应的信息。

这个场景其实就是一个简单的写时复制。对于获取在赋值过程中,获取到旧值,也是允许的。

有个疑问点就是在赋值的这个操作是不是原子的呢?

比如示例代码中的第8行。

验证代码:

package main

var (
projectMap = make(map[string]*Project)
)

func main() {
projectMap = getNewProject()
}

func getNewProject() map[string]*Project {
items := make(map[string]*Project)

item := new(Project)
item.ID = "project_id"
item.Name = "project_name"

items[item.ID] = item
return items

}

type Project struct {
ID string `json:"id"`
Name string `json:"name"`
}

在网上也找到一些资料,说是原子性的:

  • 看看开源项目都是如何做的
  • 看看一些对于Copy-On-Write的讨论

但终究还是自己探索一下的比较好对吧,哈哈。

要想看这个赋值操作是不是原子性的,那咱们看下汇编代码吧。
查看汇编,咱们分为两步:

  • 编译golang代码为.o文件
  • 反编译.o文件
PS D:\Code\Golang\github\jiankunking\cow-test> go tool compile -N -l main\main.go    
PS D:\Code\Golang\github\jiankunking\cow-test> go tool objdump .\main.o
TEXT "".main(SB) gofile..D:/Code/Golang/github/jiankunking/cow-test/main/main.go
main.go:7 0x22f1 493b6610 CMPQ 0x10(R14), SP
main.go:7 0x22f5 763e JBE 0x2335
main.go:7 0x22f7 4883ec08 SUBQ $0x8, SP
main.go:7 0x22fb 48892c24 MOVQ BP, 0(SP)
main.go:7 0x22ff 488d2c24 LEAQ 0(SP), BP
main.go:8 0x2303 e800000000 CALL 0x2308 [1:5]R_CALL:"".getNewProject
main.go:8 0x2308 833d0000000000 CMPL $0x0, 0(IP) [2:6]R_PCREL:runtime.writeBarrier+-1
main.go:8 0x230f 6690 NOPW
main.go:8 0x2311 7402 JE 0x2315
main.go:8 0x2313 eb09 JMP 0x231e
main.go:8 0x2315 48890500000000 MOVQ AX, 0(IP) [3:7]R_PCREL:"".projectMap
main.go:8 0x231c eb0e JMP 0x232c
main.go:8 0x231e 488d3d00000000 LEAQ 0(IP), DI [3:7]R_PCREL:"".projectMap
main.go:8 0x2325 e800000000 CALL 0x232a [1:5]R_CALL:runtime.gcWriteBarrier<1>
main.go:8 0x232a eb00 JMP 0x232c
main.go:9 0x232c 488b2c24 MOVQ 0(SP), BP
main.go:9 0x2330 4883c408 ADDQ $0x8, SP
main.go:9 0x2334 c3 RET
main.go:7 0x2335 e800000000 CALL 0x233a [1:5]R_CALL:runtime.morestack_noctxt
main.go:7 0x233a ebb5 JMP "".main(SB)

TEXT "".getNewProject(SB) gofile..D:/Code/Golang/github/jiankunking/cow-test/main/main.go
main.go:11 0x233c 493b6610 CMPQ 0x10(R14), SP
main.go:11 0x2340 0f8600010000 JBE 0x2446
main.go:11 0x2346 4883ec58 SUBQ $0x58, SP
main.go:11 0x234a 48896c2450 MOVQ BP, 0x50(SP)
main.go:11 0x234f 488d6c2450 LEAQ 0x50(SP), BP
main.go:11 0x2354 48c744242000000000 MOVQ $0x0, 0x20(SP)
main.go:12 0x235d e800000000 CALL 0x2362 [1:5]R_CALL:runtime.makemap_small<1>
main.go:12 0x2362 4889442428 MOVQ AX, 0x28(SP)
main.go:14 0x2367 488d0500000000 LEAQ 0(IP), AX [3:7]R_PCREL:type."".Project
main.go:14 0x236e e800000000 CALL 0x2373 [1:5]R_CALL:runtime.newobject<1>
main.go:14 0x2373 4889442430 MOVQ AX, 0x30(SP)
main.go:15 0x2378 48c740080a000000 MOVQ $0xa, 0x8(AX)
main.go:15 0x2380 833d0000000000 CMPL $0x0, 0(IP) [2:6]R_PCREL:runtime.writeBarrier+-1
main.go:15 0x2387 7402 JE 0x238b
main.go:15 0x2389 eb0c JMP 0x2397
main.go:15 0x238b 488d1500000000 LEAQ 0(IP), DX [3:7]R_PCREL:go.string."project_id"
main.go:15 0x2392 488910 MOVQ DX, 0(AX)
main.go:15 0x2395 eb11 JMP 0x23a8
main.go:15 0x2397 4889c7 MOVQ AX, DI
main.go:15 0x239a 488d1500000000 LEAQ 0(IP), DX [3:7]R_PCREL:go.string."project_id"
main.go:15 0x23a1 e800000000 CALL 0x23a6 [1:5]R_CALL:runtime.gcWriteBarrierDX
main.go:15 0x23a6 eb00 JMP 0x23a8
main.go:16 0x23a8 488b542430 MOVQ 0x30(SP), DX
main.go:16 0x23ad 8402 TESTB AL, 0(DX)
main.go:16 0x23af 48c742180c000000 MOVQ $0xc, 0x18(DX)
main.go:16 0x23b7 488d7a10 LEAQ 0x10(DX), DI
main.go:16 0x23bb 833d0000000000 CMPL $0x0, 0(IP) [2:6]R_PCREL:runtime.writeBarrier+-1
main.go:16 0x23c2 7402 JE 0x23c6
main.go:16 0x23c4 eb0d JMP 0x23d3
main.go:16 0x23c6 488d3500000000 LEAQ 0(IP), SI [3:7]R_PCREL:go.string."project_name"
main.go:16 0x23cd 48897210 MOVQ SI, 0x10(DX)
main.go:16 0x23d1 eb10 JMP 0x23e3
main.go:16 0x23d3 488d1500000000 LEAQ 0(IP), DX [3:7]R_PCREL:go.string."project_name"
main.go:16 0x23da 6690 NOPW
main.go:16 0x23dc e800000000 CALL 0x23e1 [1:5]R_CALL:runtime.gcWriteBarrierDX
main.go:16 0x23e1 eb00 JMP 0x23e3
main.go:18 0x23e3 488b542430 MOVQ 0x30(SP), DX
main.go:18 0x23e8 8402 TESTB AL, 0(DX)
main.go:18 0x23ea 488b0a MOVQ 0(DX), CX
main.go:18 0x23ed 488b7a08 MOVQ 0x8(DX), DI
main.go:18 0x23f1 48894c2440 MOVQ CX, 0x40(SP)
main.go:18 0x23f6 48897c2448 MOVQ DI, 0x48(SP)
main.go:18 0x23fb 488b5c2428 MOVQ 0x28(SP), BX
main.go:18 0x2400 488d0500000000 LEAQ 0(IP), AX [3:7]R_PCREL:type.map[string]*"".Project
main.go:18 0x2407 e800000000 CALL 0x240c [1:5]R_CALL:runtime.mapassign_faststr<1>
main.go:18 0x240c 4889442438 MOVQ AX, 0x38(SP)
main.go:18 0x2411 8400 TESTB AL, 0(AX)
main.go:18 0x2413 488b542430 MOVQ 0x30(SP), DX
main.go:18 0x2418 833d0000000000 CMPL $0x0, 0(IP) [2:6]R_PCREL:runtime.writeBarrier+-1
main.go:18 0x241f 7402 JE 0x2423
main.go:18 0x2421 eb05 JMP 0x2428
main.go:18 0x2423 488910 MOVQ DX, 0(AX)
main.go:18 0x2426 eb0a JMP 0x2432
main.go:18 0x2428 4889c7 MOVQ AX, DI
main.go:18 0x242b e800000000 CALL 0x2430 [1:5]R_CALL:runtime.gcWriteBarrierDX
main.go:18 0x2430 eb00 JMP 0x2432
main.go:19 0x2432 488b442428 MOVQ 0x28(SP), AX
main.go:19 0x2437 4889442420 MOVQ AX, 0x20(SP)
main.go:19 0x243c 488b6c2450 MOVQ 0x50(SP), BP
main.go:19 0x2441 4883c458 ADDQ $0x58, SP
main.go:19 0x2445 c3 RET
main.go:11 0x2446 e800000000 CALL 0x244b [1:5]R_CALL:runtime.morestack_noctxt
main.go:11 0x244b e9ecfeffff JMP "".getNewProject(SB)

TEXT "".init(SB) gofile..D:/Code/Golang/github/jiankunking/cow-test/main/main.go
main.go:4 0x2450 493b6610 CMPQ 0x10(R14), SP
main.go:4 0x2454 763e JBE 0x2494
main.go:4 0x2456 4883ec08 SUBQ $0x8, SP
main.go:4 0x245a 48892c24 MOVQ BP, 0(SP)
main.go:4 0x245e 488d2c24 LEAQ 0(SP), BP
main.go:4 0x2462 e800000000 CALL 0x2467 [1:5]R_CALL:runtime.makemap_small<1>
main.go:4 0x2467 833d0000000000 CMPL $0x0, 0(IP) [2:6]R_PCREL:runtime.writeBarrier+-1
main.go:4 0x246e 6690 NOPW
main.go:4 0x2470 7402 JE 0x2474
main.go:4 0x2472 eb09 JMP 0x247d
main.go:4 0x2474 48890500000000 MOVQ AX, 0(IP) [3:7]R_PCREL:"".projectMap
main.go:4 0x247b eb0e JMP 0x248b
main.go:4 0x247d 488d3d00000000 LEAQ 0(IP), DI [3:7]R_PCREL:"".projectMap
main.go:4 0x2484 e800000000 CALL 0x2489 [1:5]R_CALL:runtime.gcWriteBarrier<1>
main.go:4 0x2489 eb00 JMP 0x248b
main.go:4 0x248b 488b2c24 MOVQ 0(SP), BP
main.go:4 0x248f 4883c408 ADDQ $0x8, SP
main.go:4 0x2493 c3 RET
main.go:4 0x2494 e800000000 CALL 0x2499 [1:5]R_CALL:runtime.morestack_noctxt
main.go:4 0x2499 ebb5 JMP "".init(SB)

TEXT type..eq."".Project(SB) gofile..<autogenerated>
gofile..<autogenerated>:1 0x2713 493b6610 CMPQ 0x10(R14), SP
gofile..<autogenerated>:1 0x2717 0f8610010000 JBE 0x282d
gofile..<autogenerated>:1 0x271d 4883ec58 SUBQ $0x58, SP
gofile..<autogenerated>:1 0x2721 48896c2450 MOVQ BP, 0x50(SP)
gofile..<autogenerated>:1 0x2726 488d6c2450 LEAQ 0x50(SP), BP
gofile..<autogenerated>:1 0x272b 4889442460 MOVQ AX, 0x60(SP)
gofile..<autogenerated>:1 0x2730 48895c2468 MOVQ BX, 0x68(SP)
gofile..<autogenerated>:1 0x2735 c644241e00 MOVB $0x0, 0x1e(SP)
gofile..<autogenerated>:1 0x273a 488b542460 MOVQ 0x60(SP), DX
gofile..<autogenerated>:1 0x273f 488b5208 MOVQ 0x8(DX), DX
gofile..<autogenerated>:1 0x2743 4889542428 MOVQ DX, 0x28(SP)
gofile..<autogenerated>:1 0x2748 488b542468 MOVQ 0x68(SP), DX
gofile..<autogenerated>:1 0x274d 488b5208 MOVQ 0x8(DX), DX
gofile..<autogenerated>:1 0x2751 4889542420 MOVQ DX, 0x20(SP)
gofile..<autogenerated>:1 0x2756 4839542428 CMPQ DX, 0x28(SP)
gofile..<autogenerated>:1 0x275b 7405 JE 0x2762
gofile..<autogenerated>:1 0x275d e9b3000000 JMP 0x2815
gofile..<autogenerated>:1 0x2762 eb00 JMP 0x2764
gofile..<autogenerated>:1 0x2764 488b542460 MOVQ 0x60(SP), DX
gofile..<autogenerated>:1 0x2769 488b5218 MOVQ 0x18(DX), DX
gofile..<autogenerated>:1 0x276d 4889542420 MOVQ DX, 0x20(SP)
gofile..<autogenerated>:1 0x2772 488b542468 MOVQ 0x68(SP), DX
gofile..<autogenerated>:1 0x2777 488b5218 MOVQ 0x18(DX), DX
gofile..<autogenerated>:1 0x277b 4889542428 MOVQ DX, 0x28(SP)
gofile..<autogenerated>:1 0x2780 4839542420 CMPQ DX, 0x20(SP)
gofile..<autogenerated>:1 0x2785 7405 JE 0x278c
gofile..<autogenerated>:1 0x2787 e987000000 JMP 0x2813
gofile..<autogenerated>:1 0x278c eb00 JMP 0x278e
gofile..<autogenerated>:1 0x278e 488b542460 MOVQ 0x60(SP), DX
gofile..<autogenerated>:1 0x2793 488b5208 MOVQ 0x8(DX), DX
gofile..<autogenerated>:1 0x2797 4889542428 MOVQ DX, 0x28(SP)
gofile..<autogenerated>:1 0x279c 488b542460 MOVQ 0x60(SP), DX
gofile..<autogenerated>:1 0x27a1 488b12 MOVQ 0(DX), DX
gofile..<autogenerated>:1 0x27a4 4889542448 MOVQ DX, 0x48(SP)
gofile..<autogenerated>:1 0x27a9 488b542468 MOVQ 0x68(SP), DX
gofile..<autogenerated>:1 0x27ae 488b1a MOVQ 0(DX), BX
gofile..<autogenerated>:1 0x27b1 48895c2440 MOVQ BX, 0x40(SP)
gofile..<autogenerated>:1 0x27b6 488b4c2428 MOVQ 0x28(SP), CX
gofile..<autogenerated>:1 0x27bb 488b442448 MOVQ 0x48(SP), AX
gofile..<autogenerated>:1 0x27c0 e800000000 CALL 0x27c5 [1:5]R_CALL:runtime.memequal<1>
gofile..<autogenerated>:1 0x27c5 8844241f MOVB AL, 0x1f(SP)
gofile..<autogenerated>:1 0x27c9 84c0 TESTL AL, AL
gofile..<autogenerated>:1 0x27cb 7502 JNE 0x27cf
gofile..<autogenerated>:1 0x27cd eb41 JMP 0x2810
gofile..<autogenerated>:1 0x27cf eb00 JMP 0x27d1
gofile..<autogenerated>:1 0x27d1 488b542460 MOVQ 0x60(SP), DX
gofile..<autogenerated>:1 0x27d6 488b5218 MOVQ 0x18(DX), DX
gofile..<autogenerated>:1 0x27da 4889542428 MOVQ DX, 0x28(SP)
gofile..<autogenerated>:1 0x27df 488b542460 MOVQ 0x60(SP), DX
gofile..<autogenerated>:1 0x27e4 488b5210 MOVQ 0x10(DX), DX
gofile..<autogenerated>:1 0x27e8 4889542438 MOVQ DX, 0x38(SP)
gofile..<autogenerated>:1 0x27ed 488b542468 MOVQ 0x68(SP), DX
gofile..<autogenerated>:1 0x27f2 488b5a10 MOVQ 0x10(DX), BX
gofile..<autogenerated>:1 0x27f6 48895c2430 MOVQ BX, 0x30(SP)
gofile..<autogenerated>:1 0x27fb 488b4c2428 MOVQ 0x28(SP), CX
gofile..<autogenerated>:1 0x2800 488b442438 MOVQ 0x38(SP), AX
gofile..<autogenerated>:1 0x2805 e800000000 CALL 0x280a [1:5]R_CALL:runtime.memequal<1>
gofile..<autogenerated>:1 0x280a 8844241e MOVB AL, 0x1e(SP)
gofile..<autogenerated>:1 0x280e eb0e JMP 0x281e
gofile..<autogenerated>:1 0x2810 eb05 JMP 0x2817
gofile..<autogenerated>:1 0x2812 90 NOPL
gofile..<autogenerated>:1 0x2813 eb02 JMP 0x2817
gofile..<autogenerated>:1 0x2815 eb00 JMP 0x2817
gofile..<autogenerated>:1 0x2817 c644241e00 MOVB $0x0, 0x1e(SP)
gofile..<autogenerated>:1 0x281c eb00 JMP 0x281e
gofile..<autogenerated>:1 0x281e 0fb644241e MOVZX 0x1e(SP), AX
gofile..<autogenerated>:1 0x2823 488b6c2450 MOVQ 0x50(SP), BP
gofile..<autogenerated>:1 0x2828 4883c458 ADDQ $0x58, SP
gofile..<autogenerated>:1 0x282c c3 RET
gofile..<autogenerated>:1 0x282d 4889442408 MOVQ AX, 0x8(SP)
gofile..<autogenerated>:1 0x2832 48895c2410 MOVQ BX, 0x10(SP)
gofile..<autogenerated>:1 0x2837 e800000000 CALL 0x283c [1:5]R_CALL:runtime.morestack_noctxt
gofile..<autogenerated>:1 0x283c 488b442408 MOVQ 0x8(SP), AX
gofile..<autogenerated>:1 0x2841 488b5c2410 MOVQ 0x10(SP), BX
gofile..<autogenerated>:1 0x2846 e9c8feffff JMP type..eq."".Project(SB)
PS D:\Code\Golang\github\jiankunking\cow-test>

先从汇编代码中摘取出,第8行代码对应的汇编

main.go:8             0x2303                  e800000000              CALL 0x2308             [1:5]R_CALL:"".getNewProject        
main.go:8 0x2308 833d0000000000 CMPL $0x0, 0(IP) [2:6]R_PCREL:runtime.writeBarrier+-1
main.go:8 0x230f 6690 NOPW
main.go:8 0x2311 7402 JE 0x2315
main.go:8 0x2313 eb09 JMP 0x231e
main.go:8 0x2315 48890500000000 MOVQ AX, 0(IP) [3:7]R_PCREL:"".projectMap
main.go:8 0x231c eb0e JMP 0x232c
main.go:8 0x231e 488d3d00000000 LEAQ 0(IP), DI [3:7]R_PCREL:"".projectMap
main.go:8 0x2325 e800000000 CALL 0x232a [1:5]R_CALL:runtime.gcWriteBarrier<1>
main.go:8 0x232a eb00 JMP 0x232c

从汇编代码中可以看出,赋值的核心在下面这几句:

// 将AX寄存器中的值赋给0(IP)
main.go:8 0x2315 48890500000000 MOVQ AX, 0(IP) [3:7]R_PCREL:"".projectMap
// 跳转
main.go:8 0x231c eb0e JMP 0x232c
// 将0(IP)中值的地址赋给DI
main.go:8 0x231e 488d3d00000000 LEAQ 0(IP), DI [3:7]R_PCREL:"".projectMap

从汇编可以看到赋值是只有一步,但获取值及赋值是分开的,也就是说对于写时复制这种场景来说,直接赋值是没有问题的

基础知识补充:

MOVQ

  • movb(8位)、movw(16位)、movl(32位)、movq(64位)
  • 寄存器寻址:
movl %eax, %edx
eax -> edx

TESTB

TEST指令的行为与AND指令一样,除了不改变目的寄存器的值。例如,testq %rax, %rax 用来检查 %rax 是负数、零、还是正数。

LEAQ vs MOVQ

​https://stackoverflow.com/questions/1699748/what-is-the-difference-between-mov-and-lea​

PCDATA

CMPL

CMPL %eax,%ebx
==>
[ebx]-[eax],就是把第二个数减去第一个数

JMP

无条件转移指令
JMP 389无条件转至0x0185地址处(十进制389转换成十六进制0x0185)

CALL

调用函数
CALL runtime.printnl(SB)表示通过printnl函数的内存地址发起调用

伪计数器

FP: Frame pointer: arguments and locals.(指向当前栈帧)
PC: Program counter: jumps and branches.(指向指令地址)
SB: Static base pointer: global symbols.(指向全局符号表)
SP: Stack pointer: top of stack.(指向当前栈顶部)
注意: 栈是向下整长 golang的汇编是调用者维护参数返回值跟返回地址。所以FP的值小于参数跟返回值

本机环境

Golang写时复制是否是原子性的?_后端

x86-64( 又称x64,即英文词64-bit extended,64位拓展 的简写)是x86架构的64位拓展,向后兼容于16位及32位的x86架构。x64于1999年由AMD设计,AMD首次公开64位集以扩展给x86,称为“AMD64”。

编译命令详解

PS D:\Code\Golang\github\jiankunking\cow-test> go tool compile -help
usage: compile [options] file.go...
-% int
debug non-static initializers
-+ compiling runtime
-B disable bounds checking
-C disable printing of columns in error messages
-D path
set relative path for local imports
-E debug symbol export
-G accept generic code (default 3)
-I directory
add directory to import search path
-K debug missing line numbers
-L show full file names in error messages
-N disable optimizations
-S print assembly listing
-V print version and exit
-W debug parse tree after type checking
-asan
build code compatible with C/C++ address sanitizer
-asmhdr file
write assembly header to file
-bench file
append benchmark times to file
-blockprofile file
write block profile to file
-buildid id
record id as the build id in the export metadata
-c int
concurrency during compilation (1 means no concurrency) (default 1)
-clobberdead
clobber dead stack slots (for debugging)
-clobberdeadreg
clobber dead registers (for debugging)
-complete
compiling complete package (no C or assembly)
-cpuprofile file
write cpu profile to file
-d value
enable debugging settings; try -d help
-dwarf
generate DWARF symbols (default true)
-dwarfbasentries
use base address selection entries in DWARF (default true)
-dwarflocationlists
add location lists to DWARF in optimized mode (default true)
-dynlink
support references to Go symbols defined in other shared libraries
-e no limit on number of errors reported
-embedcfg file
read go:embed configuration from file
-gendwarfinl int
generate DWARF inline info records (default 2)
-goversion string
required version of the runtime
-h halt on error
-importcfg file
read import configuration from file
-importmap definition
add definition of the form source=actual to import map
-installsuffix suffix
set pkg directory suffix
-j debug runtime-initialized variables
-json string
version,file for JSON compiler/optimizer detail output
-l disable inlining
-lang string
Go language version source code expects
-linkobj file
write linker-specific object to file
-linkshared
generate code that will be linked against Go shared libraries
-live
debug liveness analysis
-m print optimization decisions
-memprofile file
write memory profile to file
-memprofilerate rate
set runtime.MemProfileRate to rate
-msan
build code compatible with C/C++ memory sanitizer
-mutexprofile file
write mutex profile to file
-nolocalimports
reject local (relative) imports
-o file
write output to file
-p path
set expected package import path
-pack
write to file.a instead of file.o
-r debug generated wrappers
-race
enable race detector
-shared
generate code that can be linked into a shared library
-smallframes
reduce the size limit for stack allocated objects
-spectre list
enable spectre mitigations in list (all, index, ret)
-std
compiling standard library
-symabis file
read symbol ABIs from file
-t enable tracing for debugging the compiler
-traceprofile file
write an execution trace to file
-trimpath prefix
remove prefix from recorded source file paths
-v increase debug verbosity
-w debug type checking
-wb
enable write barrier (default true)

拓展阅读

​https://stackoverflow.com/questions/70332316/whats-the-differenct-between-go-tool-compile-and-go-tool-objdump​

​https://xargin.com/plan9-assembly/​

​https://github.com/cch123/golang-notes/blob/master/assembly.md​

​https://go.dev/doc/asm​


标签:..,SP,是否是,Golang,go,MOVQ,main,gofile,写时
From: https://blog.51cto.com/jiankunking/5849452

相关文章

  • golang ratelimit限流实现
    网上找到的案例,记录一下route/init方法中:varuriLimiters=middleware.NewUriLimiter()appGroup:=g.Group("",middleware.RateLimiter(uriLimiters))//限流funcRa......
  • golang redis队列实现
    记录一下packageredisimport("bytes""encoding/json""errors")typeJobstruct{JobIdstring`json:"job_id"`Uiduint64`json:"uid"`......
  • golang处理时区
    很多Golang初学者都不知道怎么来处理时区问题.这篇文章将解释清楚一下两个问题:怎么把带时区的时间保存到数据库?在Go语言中怎么解析带时区的时间?1.数据库时区(Time......
  • golang fmt && lint
    如何轻松使用格式化和静态检查工具makefmtmakelint 1、go.mod同级目录创建文件Makefilefmt:command-vgofumpt||(WORK=$(shellpwd)&&cd/tmp&&......
  • golang内存对齐的重要性
     结构体中字段类型的改变直接造成内存对齐结果的改变,是的占用内存空间也不一样packagemainimport( "fmt" "unsafe")funcmain(){ varxxstruct{ aboo......
  • golang:break,continue,return,goto使用区别
    break条件满足,跳出整个循环continue条件满足,跳出这次循环,但继续执行后面的循环return返回数据,结束当前函数或程序运行gotogo语言的goto可以无条件的转移到程序中指......
  • Golang:error包错误处理
    (目录)1、Golangerror包内建error接口//builtin.gotypeerrorinterface{Error()string}实现error接口//errors.gopackageerrorstypeerrorStrings......
  • Golang结构体方法和接收者
    结构体方法和接收者在go语言中,没有累的概念,但是可以给类型(结构体,自定义类型)定义方法。所谓方法就是定义了接收者的函数。接收者的概念就类似于其它语言中的this或者self。......
  • 原生 HTML + CSS + JavaScript 写时钟
    时钟效果目录结构HTML代码<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge">......
  • python调用golang 从指定序列中找出一组与目标值最接近的子序列 kayb
    python调用golang从指定序列中找出一组与目标值最接近的子序列编写go代码生成so库python代码调用编写go代码写入hello.go文件packagemainimport( "C" "en......