2014-01-13 28 views
10

据我所知,如果他们太忙,goroutines会阻止其他goroutines运行。对我而言,这意味着我的应用程序的性能和响应能力很可能取决于我是否知道哪些库方法可以控制其他例程(例如,通常为Read()和Write())golang方法将产生goroutines

有什么办法可以确切地知道不同的库方法如何控制其他goroutines,即不实际阻止?

有没有什么办法可以实现一个调用第三方代码的新方法(包括像findnextchangenotification这样的依赖于waitforsingleobject或waitformultipleobjects的异步Win32 API)并且在Go调度程序中表现“很好”?在这个特定的例子中,系统调用一旦完成就会发出信号,我需要等到它完成并不耗尽所有其他goroutines。

对于如何处理Go中的第三方阻塞操作,使其不会耗尽其他例程,或许还有另一种“最佳实践”?

我假设Go运行时可能有某种内部运行在后台线程上的IO循环,以便“暂停”阻塞goroutine操作,直到它们完成IO。如果确实如此,那么我认为能够在此基础上进行新的阻塞操作会很有用。

回答

12

Go的调度程序将挂起正在等待系统调用的goroutine,并在syscall完成时唤醒它们,为您提供同步API来处理异步调用。

Read more关于调度程序如何工作。

然而,没有确定哪个goroutine会被唤醒或者从一个goroutine直接控制到另一个goroutine的确切方式 - 这是调度程序的工作。

您的担忧是Go中解决的问题,您不必担心它 - 代码不会出问题!

编辑:

为了进一步阐明;你不应该编写代码以符合(或更好地使用)Go的调度程序的语义 - 反之亦然。可能有一些代码技巧可以使您今天的性能略有提升,但调度程序可以在将来的任何Go版本中进行更改 - 使您的代码优化变得毫无用处,甚至对您不利。

+0

谢谢您的答复。我关心的不是如何让它发挥作用,而是如何使它尽可能好。在我看来,必须有某种内部事件通知循环,并将其与我自己的阻塞呼叫连接起来似乎是确保良好性能和调度的最佳方式。 – agnsaft

+0

我修改了我的答案。 – thwd

4

通过Go 1.1,goroutines只会控制阻塞调用(系统调用,通道读/写,互斥锁等)。这意味着goroutines理论上可以完全占用CPU,并且不允许调度程序运行。

在围棋1.2,改变被引入到解决这个问题:

在以前的版本中,这是循环永远也饿死了相同的线程上的其它够程一的goroutine,当GOMAXPROCS只提供了一个严重的问题用户线程。在Go 1.2中,这部分地被解决了:调度程序在进入函数时偶尔被调用。这意味着任何包含(非内联)函数调用的循环都可以被抢占,从而允许其他goroutine在同一个线程上运行。

(来源:go1.2 release notes

从理论上讲,它仍然可能有够程由从未调用非内联函数养猪的CPU,但这样的情况是要比够程,从来没有让阻塞较为少见电话,这是什么会让你之前的Go 1.2。

+0

感谢您的回复。虽然有趣并部分回答了我的问题,但我仍然想知道如何使我的自定义阻止方法以调度程序的最佳方式发挥作用?如果调度程序使用某种内部事件通知循环,应该可以将它用于自定义库吗? – agnsaft

+1

如果你想强制调度器运行,你可以调用'runtime.Gosched()'。但除非你真的发现问题,否则这可能是不值得的。 –

+0

如果您使用的是Go 1.2,除非您有没有进行任何函数调用的代码循环,否则不应该有任何问题。每个函数调用都为调度程序提供了一个跳入和“抢占”当前正在运行的goroutine的机会。编译器和运行时会找出何时真正抓住这个机会,但是你应该假设它能够智能地做出这个决定。 – joshlf

9

两种机制可以提高你的控制这一点:

  1. runtime.Gosched() - 产量控制回调度,但当然不会阻塞调用你已经发出帮助。

  2. runtime.LockOSThread()将真正的操作系统线程专用于此goroutine,没有其他任何操作系统,这意味着调度程序中的竞争会更少。从文档:

LockOSThread wires the calling goroutine to its current operating system thread. Until the calling goroutine exits or calls UnlockOSThread, it will always execute in that thread, and no other goroutine can.

+0

这很有趣,但是,不会重用现有的事件循环会更有效率吗? – agnsaft

+0

取决于这种“阻塞”goroutines的数量。从Go 1.2开始,我不认为你应该有什么担心,因为即使在IO没有被阻塞的情况下,goroutines也会执行,新的goroutines会抢占调度器(不知道这是否正确,但你明白了我的意思)。我亲自将这些东西留给调度器,除非你调用外部C库。 –

+0

调用外部C库实际上是我原来的问题的用例。 – agnsaft

相关问题