Golang使用fmt.PrintLn旋转大数字数组时出现卡顿问题

Golang使用fmt.PrintLn旋转大数字数组时出现卡顿问题 -2

我是Go语言的新手,为了练习,我正在尝试解决一个需要将数组旋转一定次数的问题。但是我的代码能够打印出包含3万个元素的结果数组,而当数组更大(8.9万个元素)时,打印就会卡住。请帮我找到解决方案。我的代码如下:

package main


    import (
    "fmt"
    "math"
    "strings"
)

func rotate(arr []string,count,elem int) string {
    if count > elem {
        count = int(math.Mod(float64(count), float64(elem)))
    }
    
    return strings.Join(arr[len(arr)-count:]," ")+" "+strings.Join(arr[:len(arr)-count]," ")
}

func main() {
    var tc,elem,rot int
    var d string
    fmt.Scanln(&tc)
    for i := 0; i < tc; i++ {
        fmt.Scan(&elem,&rot)
        myrr:=[]string{}
        for j:=0;j<elem;j++{
            fmt.Scan(&d)
            myrr=append(myrr,d)
        }
        fmt.Println(strings.Trim(rotate(myrr,rot,elem)," "))
    }
}

更多关于Golang使用fmt.PrintLn旋转大数字数组时出现卡顿问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

你好,

有什么问题吗?我无法复现这个问题。 我可以打印一个包含98k个元素的数组/切片。

        // 创建98k大小的切片
        a := make([]string, 98000)
        // 用示例数据填充 `a`
        for i := range a {
                a[i] = strconv.Itoa(i)
        }
       
        // 打印 `a`
        fmt.Println(a)

更多关于Golang使用fmt.PrintLn旋转大数字数组时出现卡顿问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


是的,你发布的那个编译器链接无法编译我的程序。它可能有一些保护措施以避免性能问题。

不过,我找到的其他在线编译器工作正常:

GDB online Debugger GDB online Debugger

GDB online Debugger | Code, Compile, Run, Debug online C, C++

Online GDB 是一个支持 C/C++ 的在线集成开发环境,包含编译器和调试器。你可以编写代码、编译、运行、调试并分享代码片段。

你好 @gucio321

感谢你的回复。

我已经在我的本地环境中尝试了你的代码,代码运行正常。但是,每当我尝试在任何在线编译器上运行时,例如 https://www.tutorialspoint.com/execute_golang_online.php,我发现它会卡住。我在多个网站上尝试过,都观察到了同样的情况。同时我还观察到,它无法扫描一个包含 98k 个输入的样本。请从这个链接下载示例文本文件:https://drive.google.com/file/d/1YzVJ_zWln10KXe3NniOJvaWwYQBIyMon/view?usp=sharing 这个输入文件在使用 Python 扫描 89k 个数字时工作正常,但在使用 Go 时会卡住。

如果你能用提供的输入文件运行我的代码,请告诉我。这里第一行表示“测试用例的数量”,第二行表示两个元素:一个是数组中要存储的元素数量,第二个是数组的旋转次数,第三行表示所有元素。

此致, Amit

问题出在fmt.Println打印大量数据时的性能瓶颈。对于8.9万个元素,每个元素都需要格式化为字符串并输出,这会导致明显的延迟。以下是优化方案:

package main

import (
	"bufio"
	"io"
	"math"
	"os"
	"strings"
)

func rotate(arr []string, count, elem int) string {
	if count > elem {
		count = int(math.Mod(float64(count), float64(elem)))
	}
	
	// 预分配结果字符串的缓冲区
	var result strings.Builder
	result.Grow(len(arr)*2) // 预估空间:每个元素+空格
	
	// 构建旋转后的字符串
	result.WriteString(strings.Join(arr[len(arr)-count:], " "))
	result.WriteString(" ")
	result.WriteString(strings.Join(arr[:len(arr)-count], " "))
	
	return result.String()
}

func main() {
	reader := bufio.NewReader(os.Stdin)
	writer := bufio.NewWriter(os.Stdout)
	defer writer.Flush()

	var tc, elem, rot int
	
	// 使用Fscan提高读取效率
	_, _ = fmt.Fscan(reader, &tc)
	
	for i := 0; i < tc; i++ {
		_, _ = fmt.Fscan(reader, &elem, &rot)
		
		myrr := make([]string, 0, elem)
		var d string
		
		for j := 0; j < elem; j++ {
			_, _ = fmt.Fscan(reader, &d)
			myrr = append(myrr, d)
		}
		
		// 直接写入缓冲输出,避免fmt.Println的性能开销
		result := strings.Trim(rotate(myrr, rot, elem), " ")
		_, _ = io.WriteString(writer, result)
		_, _ = writer.WriteString("\n")
	}
}

关键优化点:

  1. 使用bufio.Writer缓冲输出,减少系统调用次数
  2. 使用strings.Builder预分配字符串构建缓冲区
  3. io.WriteString替代fmt.Println避免格式化开销
  4. 使用bufio.Reader提高输入读取效率

对于3万个元素,原代码可能勉强运行,但8.9万个元素时fmt.Println的格式化开销会显著增加。缓冲写入直接操作字节,性能更高。

回到顶部