当我发现并不是所有的管道印刷都被打印出来时,我基于《并发中的Go》一书的示例运行以下代码。
看到“完成乘法!”丢失了。
另一方面,NumGoroutine()仅显示主要功能正在运行。
以下代码有什么问题? (https://play.golang.org/p/tkFgvKboVgS)
for user in users:
check_list.pk = None
check_list.id = None
check_list.user = user
check_list.save() # New record saved to the DB related to the user
for task in tasks:
task.pk = None
task.id = None
task.check_list = check_list
task.save() # New record saved to the DB related to the new check_list
输出:
AWSMobileClient.default().confirmForgotPassword(username: "my_username", newPassword: "MyNewPassword123!!", confirmationCode: "ConfirmationCode") { (forgotPasswordResult, error) in
if let forgotPasswordResult = forgotPasswordResult {
switch(forgotPasswordResult.forgotPasswordState) {
case .done:
print("Password changed successfully")
default:
print("Error: Could not change password.")
}
} else if let error = error {
print("Error occurred: \(error.localizedDescription)")
}
}
答案 0 :(得分:2)
有些代码路径不会打印某些done
消息。调度程序碰巧选择了一个不为multiply
打印一个。如果您稍稍更改了代码(例如,在与现在不同的实例上登录),您会发现它也可能会丢失add
done
消息。 (https://play.golang.org/p/meEPM5GR9Rr)。原因如下:
如果done
消息在生成器将数字写入通道后立即到达,并且乘法器读取了该消息,则乘法器将看到done
可用并进行选择。 multiplier
打印done
消息时就是这种情况。如果在乘法器在for循环中等待时done
消息到达,则乘法器将在输入通道(不是done
通道)上收到关闭,导致for循环终止而不打印{ {1}}消息。
出现问题是因为您要从for循环中的通道读取,然后选择。在等待for循环从通道读取时,不会评估与选择相关的任何事件。
一种更好的处理方法是不使用for循环从通道读取数据。例如:
done
答案 1 :(得分:1)
您的add
和multiply
例程不是永远循环,而是for ... range
循环。这样,在每个循环的顶部,它们等待下一个整数,而不是在select
中等待,后者从done
接收关闭或将结果发送到其流。这不是一个问题,但是这意味着如果它们的输入流被关闭,它们将返回而不会进入循环本身。
如果我add fmt.Println
calls to expose the point at which they exit due to reaching the end of their input stream,行为会稍有变化(可能是由于时机所致;我并没有因为这个而烦恼,并且Burak Serdar posted his answer在我键入此字时也已)),输出变为:< / p>
add after select
2
multiply after select
generator after select
multiply after select
add after select
4
generator after select
multiply after select
add after select
6
generator after select
Closed done
done multiply !
add got end of stream - done!
finished iterating pipeline
generator after select
done generator!
ramaining goroutines: 1
finished!
通常,使生成器本身仅生成一个done
信号,并使流水线函数始终写入其所有结果,使它们更可预测,这是更合理的。当然,无论谁正在读每个管道,都必须读到末尾,但是您已经在主goroutine中执行了此操作,因此我们将其传播到整个过程。 Here是您的代码的简化版本,采用这种方式;它输出:
2
generator after select
4
generator after select
6
generator after select
Closed done
8
generator after select
done generator!
multiply got end of stream - done!
add got end of stream - done!
finished iterating pipeline
remaining goroutines: 1
请注意,这一次,我们从最终生成的值(3)中获得了最终计算值(8)。