Golang(三)命令行工具集

Golang具有一套可以构建和处理go源代码的程序,作为命令行工具,这些程序也并非直接运行,而是由go程序调用。运行这些程序最常见的方式是作为go程序的子命令,例如 go fmt,该命令的运行方式是由go程序使用适合于包级处理的参数调用底层二进制文件,对go源代码的完整包进行操作;这些程序也可以作为独立的二进制文件运行,使用go tool子命令(如go tool cgo)使用未修改的参数;某些命令(如pprof)只能通过go tool子命令访问。go命令行作为日常开发的工具,能大大方便编译、调试、诊断程序性能等工作,本文是对常见go命令行工具使用的汇总

go命令

go命令管理go源代码并运行此处列出的其他命令。在终端输入go,会打印出如下信息

$ go

Go is a tool for managing Go source code.

Usage:

    go <command> [arguments]

The commands are:

    bug         start a bug report
    build       compile packages and dependencies
    clean       remove object files and cached files
    doc         show documentation for package or symbol
    env         print Go environment information
    fix         update packages to use new APIs
    fmt         gofmt (reformat) package sources
    generate    generate Go files by processing source
    get         add dependencies to current module and install them
    install     compile and install packages and dependencies
    list        list packages or modules
    mod         module maintenance
    run         compile and run Go program
    test        test packages
    tool        run specified go tool
    version     print Go version
    vet         report likely mistakes in packages

Use "go help <command>" for more information about a command.

Additional help topics:

    buildmode   build modes
    c           calling between Go and C
    cache       build and test caching
    environment environment variables
    filetype    file types
    go.mod      the go.mod file
    gopath      GOPATH environment variable
    gopath-get  legacy GOPATH go get
    goproxy     module proxy protocol
    importpath  import path syntax
    modules     modules, module versions, and more
    module-get  module-aware go get
    module-auth module authentication using go.sum
    module-private module configuration for non-public modules
    packages    package lists and patterns
    testflag    testing flags
    testfunc    testing functions

Use "go help <topic>" for more information about that to![]()pic.

下面介绍命令部分

启动错误报告 运行go bug命令,Bug打开默认浏览器并启动新的Bug报告,报告包括有用的系统信息

编译包和依赖项 用法如下

go build [-o output] [-i] [build flags] [packages]

build编译由导入路径命名的包及其依赖项,但不安装编译结果。如果build的参数是来自单个目录的.go文件列表,则build会将它们视为指定单个包的源文件列表;编译包时,build将忽略以"_test.go"结尾的文件

在编译单个main包时,build将生成的可执行文件写入以第一个源文件(go build ed.go rx.go 输出的二进制文件名为 'ed' 或 'ed.exe')或源代码目录(go build unix/sam 输出的二进制文件名为 'sam' 或 'sam.exe')命名的输出文件(写入Windows可执行文件时会添加.exe后缀);编译多个包或单个非main包时,build会编译包,但会丢弃生成的对象,仅用于检查包是否可编译

go build

删除对象文件和缓存文件 用法如下

go clean [clean flags] [build flags] [packages]

clean从包源目录中删除对象文件。go命令在一个临时目录中构建大多数对象,因此go clean主要关注其他go工具或通过手动调用go build留下的对象文件

go clean

展示包或符号的文档 用法

go doc [-u] [-c] [package|[package.]symbol[.methodOrField]]

go doc <pkg>
go doc <sym>[.<methodOrField>]
go doc [<pkg>.]<sym>[.<methodOrField>]
go doc [<pkg>.][<sym>.]<methodOrField>
// 在所有形式中,当匹配符号时,参数中的小写字母与任意一个大写字母都匹配,
// 但大写字母完全匹配。这意味着,如果不同的符号有不同的大小写,则包中的小写参数可能有多个匹配项。如果出现这种情况,则打印所有匹配的文档

## 例子
go doc  展示当前包的文档
go doc Foo  展示当前包中Foo的文档(Foo为首字母大写,因此不会匹配包路径)
go doc encoding/json  展示encoding/json包文档
go doc json  encoding/json缩写形式
go doc json.Number (或 go doc json.number) 展示json.Number的文档和方法摘要
go doc json.Number.Int64 (或 go doc json.number.int64)  展示json.Number中Int64方法的文档
go doc cmd/doc  显示doc命名的包文档
go doc -cmd cmd/doc  在doc命令中显示包文档和导出的符号
go doc template.new  展示html/template中New函数的文档
go doc text/template.new  一个参数,展示text/template中New函数的文档
go doc text/template new 两个参数,展示text/template中New函数的文档
go doc

打印go环境信息 用法

go env [-json] [-u] [-w] [var ...]

默认情况下,env将信息打印为shell脚本(在windows上,是批处理文件)。如果一个或多个变量名作为参数给定,env将在其自己的行上打印每个命名变量的值

go env

更新包以使用新的APIs 使用方法

go fix [packages]

fix对由导入路径命名的包运行go fix命令。fix查找使用旧api的go程序,并重写它们以使用新的api; 更新到新的go版本后,fix将帮助您对程序进行必要的更改。使用

go tool fix [-r name,...] [path ...]

如果没有显式路径,fix将读取标准输入并将结果写入标准输出; 如果命名路径是一个文件,fix会就地重写命名文件; 如果命名路径是一个目录,fix重写该目录中的所有.go文件树

gofmt(重新格式化)源码包 使用方法

go fmt [-n] [-x] [packages]

fmt在由导入路径命名的包上运行命令go fmt -l -w,它打印被修改文件的名称

-n标志打印将要执行的命令; -x标志在执行命令时打印命令

要了解更多关于gofmt细节可以运行命令go doc cmd/gofmt

通过处理源码生成go文件 使用方法

go generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages]

生成(必须显示运行)由现有文件中的指令描述的运行命令。这些命令可以运行任何进程,但其意图是创建或更新go源文件。它还接受标准的构建标志,包括-v,-n和-x: -v标志在处理过程中打印包和文件的名称; -n标志打印将要执行的命令; -x标志在执行命令时打印命令

将依赖项添加到当前模块并安装它们 使用方法

go get [-d] [-t] [-u] [-v] [-insecure] [build flags] [packages]

get解析并向当前开发模块添加依赖项,然后构建并安装它们

第一步,要解决添加哪些依赖项 对于每个命名的包或包模式,get必须决定使用相应模块的哪个版本。默认情况下,get会查找最新的标记版本,如v0.4.5或v1.2.3; 如果没有标记的发布版本,get将查找最新的标记的预发布版本,如v0.0.1-pre1; 如果根本没有标记的版本,get将查找最新的已知提交。如果在更高版本(例如,比最新版本更新的预发行版)中还不需要该模块,则get将使用它查找的版本。否则,get将使用当前所需的版本

第二步是下载(如果需要)、构建和安装命名包 如果参数命名的是模块而不是包(因为模块的根目录中没有go源代码),则会跳过该参数的安装步骤,而不会导致构建失败

go get

编译安装包和依赖项 使用方法

go install [-i] [build flags] [packages]

可执行文件安装在由GOBIN环境变量命名的目录中,如果未设置GOPATH环境变量,则默认为GOPATH/bin或HOME/go/bin; GOROOT中的可执行文件安装在GOROOT/bin或GOTOOLDIR中,而不是GOBIN中

禁用module-aware模式时,其他软件包将安装在目录GOPATH/pkg/GOOS_$GOARCH中; 启用module-aware模式时,将构建并缓存其他包,但不安装。-i标志还安装命名包的依赖项

列出包或模块 使用方法

go list [-f format] [-json] [-m] [list flags] [build flags] [packages]

list列出了命名包,每行一个。最常用的标志是-f和-json,它们控制为每个包打印的输出的形式。-f标志

使用包模板的语法指定列表的备用格式,传递给模板的结构形如

type Package struct {
        Dir           string   // 包含包源代码的目录
        ImportPath    string   // 包在目录中的导入路径
        ImportComment string   // package语句的import注释中的路径
        Name          string   // 包名称
        Doc           string   // 包文档字符串
        Target        string   // 安装路径
        Shlib         string   // 包含此包的共享库(仅在-linkshared时设置)
        Goroot        bool     // 这个包在GOROOT目录下吗?
        Standard      bool     // 这个包是标准go库的一部分吗?
        Stale         bool     // `go install`对这个包有什么作用码?
        StaleReason   string   // explanation for Stale==true
        Root          string   // 包含这个包的GOROOT或GOPATH目录
        ConflictDir   string   // $GOPATH中的这个目录shadows dir
        BinaryOnly    bool     // binary-only package (no longer supported)
        ForTest       string   // package is only for use in named test
        Export        string   // file containing export data (when using -export)
        Module        *Module  // info about package's containing module, if any (can be nil)
        Match         []string // command-line patterns matching this package
        DepOnly       bool     // package is only a dependency, not explicitly listed

        // Source files
        GoFiles         []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
        CgoFiles        []string // .go source files that import "C"
        CompiledGoFiles []string // .go files presented to compiler (when using -compiled)
        IgnoredGoFiles  []string // .go source files ignored due to build constraints
        CFiles          []string // .c source files
        CXXFiles        []string // .cc, .cxx and .cpp source files
        MFiles          []string // .m source files
        HFiles          []string // .h, .hh, .hpp and .hxx source files
        FFiles          []string // .f, .F, .for and .f90 Fortran source files
        SFiles          []string // .s source files
        SwigFiles       []string // .swig files
        SwigCXXFiles    []string // .swigcxx files
        SysoFiles       []string // .syso object files to add to archive
        TestGoFiles     []string // _test.go files in package
        XTestGoFiles    []string // _test.go files outside package

        // Cgo directives
        CgoCFLAGS    []string // cgo: flags for C compiler
        CgoCPPFLAGS  []string // cgo: flags for C preprocessor
        CgoCXXFLAGS  []string // cgo: flags for C++ compiler
        CgoFFLAGS    []string // cgo: flags for Fortran compiler
        CgoLDFLAGS   []string // cgo: flags for linker
        CgoPkgConfig []string // cgo: pkg-config names

        // Dependency information
        Imports      []string          // import paths used by this package
        ImportMap    map[string]string // map from source import to ImportPath (identity entries omitted)
        Deps         []string          // all (recursively) imported dependencies
        TestImports  []string          // imports from TestGoFiles
        XTestImports []string          // imports from XTestGoFiles

        // Error information
        Incomplete bool            // this package or a dependency has an error
        Error      *PackageError   // error loading package
        DepsErrors []*PackageError // errors loading dependencies
}

下面记录的其他列表标志控制更具体的细节

go list

模块维护 go mod提供对模块操作的访问,使用方法如下所示

go mod <command> [arguments]

注意,所有go命令都内置了对模块的支持,而不仅仅是“go mod”。例如,日常添加、删除、升级和降级依赖项都应该使用“go get”完成。command列表如下

go mod

下载模块到本地缓存 使用方法如下

go mod download [-json] [modules]

下载命名模块,可以是选择主模块依赖项的模块模式,也可以是path@version格式的模块查询。如果没有参数,download将应用于主模块的所有依赖项

go命令将在正常执行期间根据需要自动下载模块。“go mod download”命令主要用于预填充本地缓存或计算go模块代理

从工具或脚本编辑go.mod 使用方法如下

go mod edit [editing flags] [go.mod]

编辑提供了一个用于编辑go.mod的命令行接口,主要用于工具或脚本。它只读取go.mod,不查找有关模块的信息。默认情况下,edit读取和写入主模块的go.mod文件,但可以在编辑标志后指定其他目标文件。编辑标志指定一些列编辑操作

go mod edit

打印模块需求图 使用方法如下

go mod graph

图以文本形式打印模块需求图(应用的替换)。输出中的每一行都有两个空格分隔的字段:一个模块及其一个需求。每个模块都被标识为path@version格式的字符串,但主模块没有@version后缀

在当前目录下初始化新的模块 使用方法

go mod init [module]

init初始化并将新go.mod写入当前目录,实际上创建一个新的模块,该模块以当前目录为根

添加缺失的模块并移除未使用的模块 使用方法如下

go mod tidy [-v]

tidy确保go.mod与模块中的源代码匹配。它增加了构建当前模块的包和依赖项所需的任何缺少的模块,并且移除未使用的模块。它还将添加任何缺少项的go.sum并删除任何不必要的项

-v标志导致tidy将有关已删除模块的信息打印到标准错误

生成依赖项的自动生成副本 使用说明

go mod vendor [-v]

vendor重置主模块的vendor目录,以包含构建和测试所有主模块包所需的所有包。它不包括vendored的测试代码

-v标志将vendor提供的模块和包的名称打印为标准错误

验证依赖项是否具有预期内容 使用说明

go mod verify

验证检查当前模块(存储在本地下载的源缓存中)的依赖项在下载后是否未被修改。如果所有模块都未修改,验证打印“all modules verified.”,否则它报告哪些模块已被更改,并导致“go mod”以非零状态退出

解释为什么需要包或模块 使用说明

go mod why [-m] [-vendor] packages...

why在导入图中显示从主模块到列出的每个包的最短路径。如果给定了-m标志,why将参数视为模块列表,并在每个模块中找到指向任何包的路径。默认情况下,why查询与“go list all”匹配的包的graph,其中包括可访问包的测试。-vendor标志导致排除依赖项测试的原因

编译并运行go程序 使用说明

go run [build flags] [-exec xprog] package [arguments...]

run编译并运行名为main的go包。通常,包被指定为来自单个目录的.go源文件列表,但它也可能是与单个已知包匹配的导入路径、文件系统路径或模式,如“go run.”或“go run my/cmd”

默认情况下,“go run”直接运行编译后的二进制文件:“a.out arguments…”。如果给定了-exec标志,“go run”使用xprog调用二进制文件xprog a.out arguments...

测试包 使用说明

go test [build/test flags] [packages] [build/test flags & test binary flags]

go test重新编译每个包以及名称与文件模式*_test.go匹配的任何文件。这些附加文件可以包含test functions、benchmark functions和example functions。每个列出的包都会导致执行单独的测试二进制文件。文件名以_开头的文件(包括_test.go)或.被忽略

用后缀_test声明包的测试文件将被编译为单独的包,然后与主测试二进制连接并运行。go工具将会忽略名为testdata的目录,使其可以保存测试所需的辅助数据

go test的两种不同运行模式

  • 本地目录模式,在没有包参数(例如,“go test”或“go test-v”)的情况下调用go test时发生。在此模式下,go test编译当前目录中包的源码和测试文件,然后运行生成的测试二进制文件。在此模式下,将禁用缓存。在包测试完成后,go测试打印一个显示测试状态的“摘要行”(“OK”或“FAIL”)、包名和测试的时间
  • 包列表模式,在使用显式包参数(例如“go test math”、“go test ./…”、“go test”)调用go test时发生。在此模式下,go test编译并测试命令行中列出的每个包。如果包测试通过,则go测试只打印最终的“OK”摘要行。如果包测试失败,go test将打印完整的测试输出。如果使用-bench或-v标志调用,go测试打印完整的输出,甚至通过传递包测试,以便显示请求的基准测试结果或冗长日志记录。所有列出的包测试完成并打印输出后,如果存在任何一个包测试失败,go test将打印最终“FAIL”状态

仅在包列表模式下,go test缓存成功的包测试结果,以避免不必要的重复运行测试。当测试结果可以从缓存中恢复时,go test将重新显示以前的输出,而不是再次运行测试二进制文件。当发生这种情况时,go测试打印(缓存)代替汇总行中测试花费的时间

go test

运行特定的go工具 使用方式说明

go tool [-n] command [args...]

tool运行由参数标识的go tool命令,-n标志不带参数地打印已知工具的列表

go版本信息 使用说明

go version [-m] [-v] [file ...]

go version报告用于构建每个可执行文件的go版本。如果命令行中没有命名文件,则go version将打印其自己的版本信息; 如果目录被命名,go version将遍历该目录,递归地查找识别的go二进制文件并报告它们的版本。默认情况下,go version不会报告在目录扫描期间发现的无法识别的文件

-v标志 报告无法识别的文件

-m标志 go version在可用时打印每个可执行文件的嵌入模块版本信息。在输出中,模块信息由版本行后面的多行组成,每行由一个前导制表符缩进

报告包中可能出现的错误 使用方法说明

go vet [-n] [-x] [-vettool prog] [build flags] [vet flags] [packages]

vet对由导入路径命名的包运行go vet命令

构建模式

go buildgo install命令采用-buildmode参数,该参数指示要生成哪种类型的对象文件。当前支持的值为

build modes

环境变量

go命令及其调用的工具用于配置参考环境变量。如果环境变量未设置,则go命令使用合理的默认设置。要查看变量<NAME>的有效设计可以运行go env <NAME>; 要更改变量<NAME>的默认设计,运行命令go env -w <NAME>=<VALUE>

通用环境变量

go env general-purpose

用于cgo的环境变量

go env cgo

特定于体系结构的环境变量

go env arch

特殊用途的环境变量

go env special

go env中提供但未从环境中读取的其他信息

go env additional

逻辑和性能诊断工具

go生态系统提供了大量的API和工具来诊断go程序中的逻辑和性能问题,这一节是对这些可用工具的总结

诊断解决方案可以分为以下几类

  • 性能分析 这类工具用于分析go程序的复杂性和成本,例如通过它的内存使用和频繁调用的函数来标识go程序的开销部分
  • 追踪 是一种在调用或用户请求的整个生命周期中检测代码以分析延迟的方法,它提供了每个组件对系统的总延迟概述,可以跨越多个go进程进行
  • 调试 允许我们暂停go程序并检查其执行。程序状态和流程可以通过调试来验证
  • 运行时统计和事件 运行时统计和事件的收集和分析为go程序的健康提供了高层次的概述。尖峰/度量的监控指标有助于识别吞吐量、利用率和性能的变化

Tips 一些诊断工具可能相互干扰。例如,精准内存剖析可能影响CPU性能分析的准确性、goroutine阻塞分析会影响调度器跟踪。因此,单独使用工具获取更精确的信息

性能分析 对于识别昂贵的或频繁调用的代码段非常有用。go运行时以pprof可视化工具提供所期望格式的性能分析数据。在测试期间,也可以通过go test或net/http/pprof包中提供的endpoints来收集性能分析数据
由runtime/pprof预定义配置文件

  • cpu 决定了程序在actively状态(而不是在sleeping或waiting I/O)时花费的cpu时间
  • heap 报告内存分配示例;用于监视当前和历史内存使用情况,并检查内存泄漏
  • threadcreate 报告程序中引导创建新线程的部分
  • goroutine 报告当前所有goroutine的堆栈跟踪
  • block 显示goroutine阻塞等待同步原语(包括timer channels),block profile默认为未启用状态,使用runtime.SetBlockProfileRate可以启用它
  • mutex 报告锁争用。当您认为由于互斥争用导致CPU未充分利用时,请使用此profile。默认情况下mutex profile处于未启用状态,通过runtime.SetMutexProfileFraction可以启用它

其他分析器 在Linux上,可以使用perf工具分析go程序,perf可以配置和解开cgo/SWIG代码和内核,因此可以深入了解native/kernel性能瓶颈; 在MacOS上,可以使用Instruments分析go程序

生产服务性能分析 分析生产中的程序是安全的,但是启用某些profile(例如CPU profile)会增加成本。您可能想要定期分析生产服务性能问题,特别是在具有单个进程的多个副本的系统中,周期性地随机挑选一个副本是安全的选择。选择一个生产进程,每隔Y秒分析并保存它的结果以进行可视化分析;然后定期重复。可以手动和/或自动检查结果以发现问题。性能收集可能相互干扰,因此建议每次只收集单个概要文件

可视化数据分析方法 go使用go tool pprof工具提供text、graph和callgrind可视化

自定义profile go用户可以通过运行时提供的pprof.Profile创建他们的自定义配置文件,并使用现有的工具来检查它们。如下示例将监听7777端口并以 /custom_debug_path/profile endpoint,为pprof.Profile提供服务

package main

import (
    "log"
    "net/http"
    "net/http/pprof"
)

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/custom_debug_path/profile", pprof.Profile)
    log.Fatal(http.ListenAndServe(":7777", mux))
}

追踪 这是一种在调用链的整个生命周期中检测代码以分析时延的方法,go提供golang.org/x/net/trace包作为每个go节点的最小跟踪后端,并用一个简单的dashboard提供一个最小的检测库,go还提供了一个可执行的Tracer来追踪间隔期间内运行时事件。追踪可以为我们提供

  • 检测并分析go进程中的应用程序延迟
  • 在一个很长的调用链中测量特定调用的成本
  • 找出利用率并改进性能。没有跟踪数据,瓶颈并不总是显而易见

在单体系统中,从程序的构建块收集诊断数据相对容易,所有模块都在一个进程中,并共享公共资源来报告日志、错误和其他诊断信息。一旦系统由单体进程扩展到分布式微服务,就很难定位从前端Web服务器到所有后台的调用,以及响应返回给用户。这也是分布式追踪在测试和分析生产系统方面发挥重要作用的地方

分布式追踪是一种在用户请求的整个生命周期中检测代码以分析延迟的方法。当系统是分布式的,并且传统的分析和调试工具无法扩展时,您可能希望使用分布式跟踪工具来分析用户请求和RPC的性能。分布式追踪系统是我们能够

  • 在大型系统中检测并分析应用程序延迟
  • 跟踪用户请求生命周期内的所有RPC,并查看仅在生产中可见的集成问题
  • 找出可以应用于我们系统的性能改进。在跟踪数据收集之前,许多瓶颈是不明显的

go生态系统为每个追踪系统提供了不同的分布式跟踪库和对后端透明的库
调试 调试是识别程序错误行为的过程,调试器允许我们了解程序的执行流程和当前状态。go用户主要使用以下调试器

  • **Delve ** 作为go编程语言的调试器,它支持go的运行时概念和内置类型。Delve正试图成为一个功能齐全的可靠的go程序调试器
  • GDB go通过标准go编译器和gccgo提供GDB支持。堆栈管理、线程和运行时包含不同于执行模型的方面,GDB可能混淆调试器,即使程序是用gccgo编译的。尽管GDB可以用来调试go程序,但它并不理想,可能会造成混乱

运行时统计和事件 运行时提供用户内部事件的统计和报告,以便在运行时级别诊断性能和使用问题。用户可以监视这些统计信息,以便更好地了解go程序的整体健康和性能。一些经常监视的统计数据和状态

  • runtime.ReadMemStats 报告与堆分配和垃圾收集相关的度量指标。内存统计对于监视进程消耗多少内存资源、进程是否可以充分利用内存以及捕获内存泄漏是有用的
  • debug.ReadGCStats 读取垃圾收集的统计信息。查看gc暂停上花费了多少资源是很有用的。它还报告了垃圾收集器暂停和暂停时间百分比的时间线
  • debug.Stack 返回当前堆栈跟踪,堆栈跟踪对于查看当前正在运行的goroutine的数量、它们正在执行的操作以及它们是否被阻止非常有用
  • debug.WriteHeapDump 暂停所有goroutine的执行并允许您将堆转储到文件。堆转储是在给定时间内go进程内存的快照。它包含所有分配的对象以及goroutine、finalizers等
  • runtime.NumGoroutine 返回当前goroutine的数目。可以监视该值以查看是否有足够的goroutine供使用,或检测goroutine泄漏

go附带运行时Execution Tracer来捕获大量运行时事件。调度、SysCall、垃圾回收、堆大小和其他事件由运行时收集,并可用于go工具跟踪可视化。Tracer可用于

  • 了解goroutine如何执行
  • 了解一些核心运行时事件,例如GC
  • 识别并行性差的执行

小结

go提供了丰富的命令行和工具,在日常运维开发中熟练使用命令/工具能够大大提升效率。本文是关于命令行和常用工具的简单总结,希望能对您有所帮助

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • 一、Python简介和环境搭建以及pip的安装 4课时实验课主要内容 【Python简介】: Python 是一个...
    _小老虎_阅读 5,726评论 0 10
  • 本文简单介绍 Golang 提供的命令。我们执行 go help [command] 可以查看具体命令的帮助信息。...
    juniway阅读 1,987评论 0 2
  • 大多数 Nginx 新手都会频繁遇到这样一个困惑,那就是当同一个location配置块使用了多个 Nginx 模块...
    SkTj阅读 7,621评论 0 12
  • 我们都是阴沟里的虫子,但总还是得有人仰望星空。 前一阵子有个新闻,柯洁以0:4输给了阿尔法狗。如果你不知道柯洁是谁...
    新月饭店大小姐阅读 463评论 0 0
  • “财富,是你积累下来的东西,而不是你花掉的东西。” 在我们身边,500多名富翁现身说法。他们不说,却一直在...
    菜花田阅读 589评论 1 4