Lua笔记(2)

Lua程序的源代码可以从官网下载,直接make就好。如果遇到“fatal error: readline/readline.h: No such file or directory”的编译错误,请参考这篇文章

如果想自己使用gdb研究代码,可以把src/Makefile中的CFLAGS一行修改如下:

CFLAGS= -g -Wall -Wextra -DLUA_COMPAT_5_2 $(SYSCFLAGS) $(MYCFLAGS)

源码编译完完会生成两个可执行文件:lualuaclua就是语言的解释器,而luac则是编译器,它会把lua程序转换成字节码。

当在命令行执行lua命令时:

[root@Fedora lua-5.3.1]# lua
Lua 5.3.1  Copyright (C) 1994-2015 Lua.org, PUC-Rio
>

在另一个窗口使用pstack命令查看lua进程:

[root@Fedora lua-5.3.1]# pstack 3368
#0  0x00007f8039c2a2d0 in __read_nocancel () from /lib64/libc.so.6
#1  0x00007f8039f2489d in rl_getc () from /lib64/libreadline.so.6
#2  0x00007f8039f25197 in rl_read_key () from /lib64/libreadline.so.6
#3  0x00007f8039f0ec6c in readline_internal_char () from /lib64/libreadline.so.6
#4  0x00007f8039f0f3e5 in readline () from /lib64/libreadline.so.6
#5  0x000000000040460f in pushline (L=0x233e018, firstline=1) at lua.c:310
#6  0x00000000004048b3 in loadline (L=0x233e018) at lua.c:377
#7  0x0000000000404a54 in doREPL (L=0x233e018) at lua.c:411
#8  0x00000000004051a6 in pmain (L=0x233e018) at lua.c:588
#9  0x000000000040a848 in luaD_precall (L=0x233e018, func=0x233e700, nresults=1) at ldo.c:337
#10 0x000000000040acec in luaD_call (L=0x233e018, func=0x233e700, nResults=1, allowyield=0) at ldo.c:421
#11 0x00000000004075cb in f_call (L=0x233e018, ud=0x7ffc9fae64e0) at lapi.c:919
#12 0x0000000000409ec5 in luaD_rawrunprotected (L=0x233e018, f=0x407594 <f_call>, ud=0x7ffc9fae64e0) at ldo.c:142
#13 0x000000000040b4a7 in luaD_pcall (L=0x233e018, func=0x407594 <f_call>, u=0x7ffc9fae64e0, old_top=16, ef=0) at ldo.c:644
#14 0x000000000040769a in lua_pcallk (L=0x233e018, nargs=2, nresults=1, errfunc=0, ctx=0, k=0x0) at lapi.c:945
#15 0x0000000000405273 in main (argc=1, argv=0x7ffc9fae6628) at lua.c:607

可以看到lua程序阻塞在doREPL函数,等待用户输入。

Go语言runtime.Gosched()函数浅析

Go语言runtime.Gosched()函数的官方文档如下:

func Gosched

    func Gosched()
Gosched yields the processor, allowing other goroutines to run. It does not suspend the current goroutine, so execution resumes automatically.

这个函数的作用是让当前goroutine让出CPU,好让其它的goroutine获得执行的机会。同时,当前的goroutine也会在未来的某个时间点继续运行。

请看下面这个例子(show.go):

package main

import (
    "fmt"
)

func showNumber (i int) {
    fmt.Println(i)
}

func main() {

    for i := 0; i < 10; i++ {
        go showNumber(i)
    }

    fmt.Println("Haha")
}

执行结果如下:

[root@Fedora goEx]# go build show.go
[root@Fedora goEx]# ./show
Haha

没有打印出数字,可以看到goroutine没有获得机会运行。

修改代码:在main函数中加上runtime.Gosched()

package main

import (
    "fmt"
    "runtime"
)

func showNumber (i int) {
    fmt.Println(i)
}

func main() {

    for i := 0; i < 10; i++ {
        go showNumber(i)
    }

    runtime.Gosched()
    fmt.Println("Haha")
}

编译运行:

[root@Fedora goEx]# go build show.go
[root@Fedora goEx]# ./show
0
1
2
3
4
5
6
7
8
9
Haha

可以看到goroutine获得了运行机会,打印出了数字。

参考资料:
(1)Gosched
(2)What exactly does runtime.Gosched do?

Go程序编译简介

Go语言安装包自带的编译器是gc。针对不同的硬件平台,Go分别提供了一组编译工具包:比如,6a6c6g6l就是针对X86-64平台(5*ARM8*X86)。此外gcc还有一个支持Go语言的前端:gccgo。因此如果gc不支持你当前的平台,可以尝试用gcc

go build命令默认会使用gc编译器。假设当前目录为goEx,在这个目录下创建hello.go

package main

import "fmt"

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

在当前目录下执行go build命令:

[root@Fedora goEx]# ls
hello.go
[root@Fedora goEx]# go build
[root@Fedora goEx]# ls
goEx  hello.go
[root@Fedora goEx]# ./goEx
Hello, world!

可以看到生成的可执行文件名字为goEx,与目录名相同。

因为hello.gomain package,执行go build hello.go会生成名为hello的可执行文件:

[root@Fedora goEx]# go build hello.go
[root@Fedora goEx]# ls
hello  hello.go

也可以使用-o选项指定可执行文件名字:

[root@Fedora goEx]# go build -o a.out hello.go
[root@Fedora goEx]# ls
a.out  hello.go
[root@Fedora goEx]# ./a.out
Hello, world!