为了账号安全,请及时绑定邮箱和手机立即绑定

计算 Go 中切片中字符的出现次数

计算 Go 中切片中字符的出现次数

Go
慕工程0101907 2021-09-13 16:58:00
好的,所以我撞到了一堵砖墙。编辑:bytes.IndexByte()在我的count()函数中 使用使其运行速度几乎快两倍。bytes.IndexByte()是用汇编而不是 Go 编写的。仍然不是C速度,但更接近。我有两个程序,一个在 C 中,一个在 Go 中,它们都计算文件中的换行符。超级简单。在 2.4GB 的文件上,C 程序运行约 1.5 秒,Go 运行约 4.25 秒。我是否达到了 Go 的速度限制?如果是这样,究竟是什么导致了这种情况?我能读 C,但我不能读汇编,所以比较 C 的 asm 和 Go 的 asm 对我没有太大作用,只是表明 Go 有大约 400 多行(忽略 .ascii 部分)。虽然我知道 Go 无法逐步匹配 C,但我不会假设速度会降低 4 倍。想法?这是 Go 的 cpuprofile:这是 C (编译 w/ gcc -Wall -pedantic -O9)#include <stdio.h>#include <stdlib.h>#include <stdint.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <errno.h>#define BUFFER_SIZE (16 * 1024)intmain(){    const char *file = "big.txt";    int fd = open (file, O_RDONLY);    char buf[BUFFER_SIZE + 1];    uintmax_t bytes;    size_t bytes_read;    size_t lines;    posix_fadvise (fd, 0, 0, POSIX_FADV_SEQUENTIAL);    while ((bytes_read = safe_read (fd, buf, BUFFER_SIZE)) > 0)    {        char *p = buf;        // error checking        while ((p = memchr (p, '\n', (buf + bytes_read) - p)))          {            ++p;            ++lines;          }        bytes += bytes_read;    }    printf("%zu\n", bytes);    printf("%zu\n", lines);    return 0;}
查看完整描述

2 回答

?
森栏

TA贡献1810条经验 获得超5个赞

这是一种不太难也不太慢的方法,使用bytes.IndexByte(因为你发现 Go 的 asm 实现有帮助)和syscall.Mmap:


package main


import (

    "bytes"

    "fmt"

    "log"

    "os"

    "syscall"

)


func main() {

    if len(os.Args) < 2 {

        log.Fatal("pass filename on command line")

    }

    f, err := os.Open(os.Args[1])

    if err != nil {

        log.Fatal("open: ", err)

    }

    stat, err := f.Stat()

    if err != nil {

        log.Fatal("stat: ", err)


    }

    data, err := syscall.Mmap(int(f.Fd()), 0, int(stat.Size()), syscall.PROT_READ, syscall.MAP_SHARED)

    if err != nil {

        log.Fatal("mmap: ", err)

    }

    newlines := 0

    for {

        i := bytes.IndexByte(data, 10)

        if i == -1 {

            break

        }

        newlines++

        data = data[i+1:]

    }

    fmt.Println(newlines)

}

Mmap 看起来很奇怪,但在这里就像您将文件读入一个切片一样,除了由于操作系统的帮助而占用的资源较少。


您可以在没有太多工作的情况下并行计数,但我不确定这是否值得。(amd64例如,如果单核计数受到内存带宽的限制,如果增益为零或负值,我不会感到震惊,但这对我来说测试速度并不快。)


查看完整回答
反对 回复 2021-09-13
  • 2 回答
  • 0 关注
  • 165 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信