优化 goroutine 和 channel:最小化输出数字时间

需积分: 0 0 下载量 116 浏览量 更新于2024-08-04 收藏 685KB DOCX 举报
"第六次作业1 - goroutine和channel练习" 在这个编程练习中,主要涉及的是Go语言中的并发编程概念,特别是如何有效地使用goroutines(轻量级线程)和channels来提高程序的执行效率。题目要求在有限的资源消耗下,通过优化goroutines和channels的使用,使得输出所有自然数所需时间最短。 首先,问题的核心在于如何平衡生成自然数、计算平方以及输出数字这三个操作的时间。由于生成自然数需要200毫秒,计算平方需要500毫秒,输出数字需要300毫秒,所以需要设计一种方式,使得这些操作能够并行执行,从而减少总的执行时间。 解决方案是利用goroutines和channels。在Go中,goroutines允许并发执行任务,而channels可以用来在goroutines之间传递数据。在这个例子中,我们需要一个counter goroutine生成自然数,多个squarer goroutines计算平方,以及多个printer goroutines负责输出数字。 根据题目描述,counter需要生成一个自然数后立即发送到channel,然后等待下一个200毫秒。对于squarers,由于计算一个平方需要500毫秒,所以需要至少3个才能保证不会阻塞。同样,printer也需要至少2个,因为输出一个数字需要300毫秒。这样,当counter生成第4个数字时,前3个数字已经完成平方计算,可以依次被打印机处理,从而实现并发最大化。 为了确保程序的正确执行,使用了两个sync.WaitGroup。waitGroutp用于在main函数中等待所有printer goroutines完成输出,而waitGroutp2则用于在所有数字输出完成后关闭squares通道。关闭通道是一个重要的步骤,因为它可以通知所有等待读取该通道的goroutines操作已完成,避免死锁。 然而,原程序存在潜在的死锁问题,因为当所有数字输出完毕后,如果printer goroutine仍在尝试从channel中读取数据,可能会导致阻塞。为了解决这个问题,可以使用`select{}`配合`case <-in:`来监听channel,当channel关闭时,`in==nil`的情况会被default分支捕获,从而避免了死锁。 改写后的代码确保了在输出最后一个数字后,所有goroutines能够正常结束,且不会持续输出无效数据。 测试显示,程序的执行时间基本符合预期,即20.8秒,额外的0.07秒可能是由于其他非主要操作的开销。虽然死锁的概率较低,但通过改写可以进一步提高程序的健壮性。 这个练习展示了如何在Go中有效地使用并发工具,如goroutines和channels,以优化性能并避免潜在的问题。理解这种并发模式对于编写高效、可靠的Go代码至关重要。