RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1566416
Accepted
Space Researcher
Space Researcher
Asked:2024-02-15 17:08:43 +0000 UTC2024-02-15 17:08:43 +0000 UTC 2024-02-15 17:08:43 +0000 UTC

Python3和Golang在向2个文件写入数字的任务中速度的主观比较

  • 772

我用两种语言编写了相同的代码:

import os

file1 = open("z1.txt", "w")
file2 = open("z2.txt", "w")

for x in range(-1000, 1000):
    for y in range(-1000, 1000):
        z1 = (x + y) * (x + y)
        z2 = x * y

        args = str(x) + "\t" + str(y) + "\t"
        toFile1 = args + str(z1) + "\n"
        toFile2 = args + str(z2) + "\n"
        file1.write(toFile1)
        file2.write(toFile2)

file1.close()
file2.close()
package main

import (
  "os"
  "strconv"
)

func main() {
  file1, _ := os.Create("z1.txt")
  file2, _ := os.Create("z2.txt")
  for x := -1000; x < 1000; x++ {
    for y := -1000; y < 1000; y++ {
      z1 := (x + y) * (x + y)
      z2 := x * y

      args := strconv.Itoa(x) + "\t" + strconv.Itoa(y) + "\t"
      toFile1 := []byte(args + strconv.Itoa(z1) + "\n")
      toFile2 := []byte(args + strconv.Itoa(z2) + "\n")
      file1.Write(toFile1)
      file2.Write(toFile2)
    }
  }
  file1.Close()
  file2.Close()
}

一个意外的惊喜——在 golang 上,最坏情况下运行时间为 12 秒,而在 python 中则为 7 秒。在平均情况下,go 也远远落后,大约进行了 30 次运行。此外,golang 本身在该程序中以 2 个线程工作,这似乎可以加快写入两个文件的速度。

我怀疑我在 Go 中错误地使用了太低级的函数,并决定在 C 中实现相同的代码:

#include "stdio.h"

int main(){
    FILE* f1 = fopen("z1.txt","w");
    FILE* f2 = fopen("z2.txt","w");


    for (int x =-1000; x <1000;++x ){
        for(int y =-1000; y <1000;++y ){
            int z1 = (x+y)*(x+y);
            int z2 = x*y;

            fprintf(f1,"%d\t%d\t%d\n",x,y,z1);
            fprintf(f2,"%d\t%d\t%d\n",x,y,z2);
        }
    }
    fclose(f1);
    fclose(f2);

    return 0;
}

这里没有什么令人惊讶的——它会在瞬间完成所有事情。好吧,我尝试了 GoS 实现,它变得更糟 - 平均 22 秒。

package main

import (
    "fmt"
    "os"
)

func main() {
    file1, _ := os.Create("z1.txt")
    file2, _ := os.Create("z2.txt")

    for x := -1000; x < 1000; x++ {
        for y := -1000; y < 1000; y++ {
            z1 := (x + y) * (x + y)
            z2 := x * y

            fmt.Fprintf(file1, "%d\t%d\t%d\n", x, y, z1)
            fmt.Fprintf(file2, "%d\t%d\t%d\n", x, y, z2)
        }
    }
    file1.Close()
    file2.Close()
}

接下来,我尝试优化 Go 中的代码并写入文件 1 次,而不是循环写入,并将缓冲区存储在一行中,我在 Python 中做了同样的事情,但没有任何改变,我无法理解出了什么问题,为什么 golang 在这项任务上落后了。

带 Go 手写缓冲区的版本:

package main

import (
    "os"
    "strconv"
)

func main() {
    file1, _ := os.Create("z1.txt")
    file2, _ := os.Create("z2.txt")
    var toFile1 string
    var toFile2 string
    for x := -1000; x < 1000; x++ {
        for y := -1000; y < 1000; y++ {
            z1 := (x + y) * (x + y)
            z2 := x * y

            args := strconv.Itoa(x) + "\t" + strconv.Itoa(y) + "\t"
            toFile1 += (args + strconv.Itoa(z1) + "\n")
            toFile2 += (args + strconv.Itoa(z2) + "\n")

        }
    }

    file1.Write([]byte(toFile1))
    file2.Write([]byte(toFile2))

    file1.Close()
    file2.Close()
}

如果可能的话,请给出详细的答案,而不是“在go中还有一个额外的动作——转换为字节”。先感谢您)

python3 Python 3.10.12(主要,2023 年 11 月 20 日,15:14:05)[GCC 11.4.0] 在 Linux 上键入“help”、“copyright”、“credits”或“license”以获取更多信息。

go版本go1.21.6 linux/amd64

python
  • 1 1 个回答
  • 94 Views

1 个回答

  • Voted
  1. Best Answer
    Stanislav Volodarskiy
    2024-02-15T20:02:54Z2024-02-15T20:02:54Z

    Go 中的文件没有缓冲区。对文件的每次写操作都会导致对磁盘的写入。在从操作系统收到数据已写入磁盘的保证后,程序接收控制。测试:

    $ time go run temp.go 
    
    real  0m12.011s
    user  0m4.660s
    sys   0m7.384s
    

    排队时间长sys- 将数据写入磁盘的等待时间。

    让我们添加缓冲区:

    package main
    
    import (
      "bufio"
      "os"
      "strconv"
    )
    
    func main() {
      file1, _ := os.Create("z1.txt")
      file2, _ := os.Create("z2.txt")
      buf1 := bufio.NewWriter(file1)
      buf2 := bufio.NewWriter(file2)
      for x := -1000; x < 1000; x++ {
        for y := -1000; y < 1000; y++ {
          z1 := (x + y) * (x + y)
          z2 := x * y
    
          args := strconv.Itoa(x) + "\t" + strconv.Itoa(y) + "\t"
          toFile1 := []byte(args + strconv.Itoa(z1) + "\n")
          toFile2 := []byte(args + strconv.Itoa(z2) + "\n")
          buf1.Write(toFile1)
          buf2.Write(toFile2)
        }
      }
      buf1.Flush()
      buf2.Flush()
      file1.Close()
      file2.Close()
    }
    

    它变得好多了:

    $ time go run temp.go 
    
    real  0m1.554s
    user  0m1.428s
    sys   0m0.112s
    

    在Python和C中,缓冲区直接构建到文件对象中,您可以立即获得良好的性能,但不能保证在写入时正确写入数据。该保证仅在缓冲区重置后出现。

    对于方向,你的 C 代码对我来说几乎与缓冲的 Go 一样:

    $ time ./a.out 
    
    real  0m1.336s
    user  0m1.168s
    sys   0m0.080s
    

    但是如果将缓冲区重置添加到 C 中的循环 ( fflush(f1); fflush(f2);) 中会发生什么?再次,等待录制的七秒:

    $ time ./a.out 
    
    real  0m11.220s
    user  0m4.220s
    sys   0m6.912s
    
    • 7

相关问题

  • 是否可以以某种方式自定义 QTabWidget?

  • telebot.anihelper.ApiException 错误

  • Python。检查一个数字是否是 3 的幂。输出 无

  • 解析多个响应

  • 交换两个数组的元素,以便它们的新内容也反转

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5