- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
(我不认为我的问题是此 QA 的重复:go routine blocking the others one,因为我正在运行 Go 1.9,它具有抢占式调度程序,而该问题是针对 Go 1.2 提出的)。
我的 Go 程序调用了一个由另一个 Go-lang 库包装的 C 库,该库发出的阻塞调用可能会持续 60 多秒。我想添加一个超时,以便它在 3 秒内返回:
长 block 的旧代码:
// InvokeSomething is part of a Go wrapper library that calls the C library read_something function. I cannot change this code.
func InvokeSomething() ([]Something, error) {
ret := clib.read_something(&input) // this can block for 60 seconds
if ret.Code > 1 {
return nil, CreateError(ret)
}
return ret.Something, nil
}
// This is my code I can change:
func MyCode() {
something, err := InvokeSomething()
// etc
}
我的代码带有 go-routine、 channel 和超时,基于这个 Go 示例:https://gobyexample.com/timeouts
type somethingResult struct {
Something []Something
Err error
}
func MyCodeWithTimeout() {
ch = make(chan somethingResult, 1);
go func() {
something, err := InvokeSomething() // blocks here for 60 seconds
ret := somethingResult{ something, err }
ch <- ret
}()
select {
case result := <-ch:
// etc
case <-time.After(time.Second *3):
// report timeout
}
}
但是当我运行 MyCodeWithTimeout
它仍然需要 60 秒才能执行 case <-time.After(time.Second * 3)
block 。
I know that attempting to read from an unbuffered channel with nothing in it会阻塞,但我创建了缓冲大小为 1
的 channel 据我所知,我做得对。我很惊讶 Go 调度程序没有抢占我的 goroutine,或者这是否取决于在 go-lang 代码中执行而不是外部 native 库?
我读到 Go 调度程序,至少在 2015 年,实际上是“半抢占式”的,它不会抢占“外部代码”中的操作系统线程:https://github.com/golang/go/issues/11462
you can think of the Go scheduler as being partially preemptive. It's by no means fully cooperative, since user code generally has no control over scheduling points, but it's also not able to preempt at arbitrary points
我听说runtime.LockOSThread()
可能会有帮助,所以我将函数更改为:
func MyCodeWithTimeout() {
ch = make(chan somethingResult, 1);
defer close(ch)
go func() {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
something, err := InvokeSomething() // blocks here for 60 seconds
ret := somethingResult{ something, err }
ch <- ret
}()
select {
case result := <-ch:
// etc
case <-time.After(time.Second *3):
// report timeout
}
}
...但是它根本没有帮助,它仍然阻塞了 60 秒。
最佳答案
您提出的在 MyCodeWithTimeout()
中启动的 goroutine 中进行线程锁定的解决方案不能保证 MyCodeWithTimeout()
将在 3 秒后返回,以及这样做的原因是第一点:不能保证启动的 goroutine 会被调度并到达将线程锁定到 goroutine 的点,其次:因为即使调用外部命令或系统调用并在 3 秒内返回,也不能保证其他运行 MyCodeWithTimeout()
的 goroutine 将被安排接收结果。
而是在 MyCodeWithTimeout()
中执行线程锁定,而不是在它启动的 goroutine 中:
func MyCodeWithTimeout() {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
ch = make(chan somethingResult, 1);
defer close(ch)
go func() {
something, err := InvokeSomething() // blocks here for 60 seconds
ret := somethingResult{ something, err }
ch <- ret
}()
select {
case result := <-ch:
// etc
case <-time.After(time.Second *3):
// report timeout
}
}
现在如果 MyCodeWithTimeout()
开始执行,它会将 goroutine 锁定到 OS 线程,您可以确定这个 goroutine 会注意到定时器值上发送的值。
注意:如果您希望它在 3 秒内返回,这会更好,但是这个窗台不能提供保证,因为触发的计时器(在其 channel 上发送一个值)会自行运行goroutine,这个线程锁对那个goroutine的调度没有影响。
如果你想要保证,你不能依赖于其他 goroutines 给出“退出”信号,你只能依赖于运行 MyCodeWithTimeout()
函数的 goroutine 中发生的这种情况(因为自从你做了线程锁定,你可以确定它被安排了)。
提高给定 CPU 核心的 CPU 使用率的“丑陋”解决方案是:
for end := time.Now().Add(time.Second * 3); time.Now().Before(end); {
// Do non-blocking check:
select {
case result := <-ch:
// Process result
default: // Must have default to be non-blocking
}
}
请注意使用 time.Sleep()
的“冲动”在这个循环中会取消保证,因为 time.Sleep()
可能会在其实现中使用 goroutines,当然不能保证在给定的持续时间后准确返回。
另请注意,如果您有 8 个 CPU 内核和 runtime.GOMAXPROCS(0)
为你返回 8,而你的 goroutines 仍然“饥饿”,这可能是一个临时解决方案,但你在你的应用程序中使用 Go 的并发原语(或缺乏使用它们)仍然有更严重的问题,你应该调查和“修复”那些。将线程锁定到一个 goroutine 甚至可能会使其他 goroutine 的情况变得更糟。
关于go - 如何使阻塞的外部库调用超时?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48604783/
对于一个简单的聊天程序,我使用了一个通过 boost::python 包装的 c 库。 使用 PyQT 编写了一个简单的 GUI。接收消息是通过阻塞调用完成的lib说。对于独立刷新的 GUI,通信部分
当我创建以下内容时,我试图创建一个可以被异常终止的线程类(因为我试图让线程等待一个事件): import sys class testThread(threading.Thread): def
我正在用 Haskell 编写服务器,我想在客户端断开连接后显式关闭它们。当我调用 hClose ,线程将阻塞,直到客户端关闭其一侧的句柄。有没有办法让它在不阻塞的情况下关闭? 提前致谢! 最佳答案
这个问题已经有答案了: 已关闭12 年前。 Possible Duplicate: garbage collection Operation 我有几个相关问题。 1.JAVA垃圾收集器运行时,是否占用
我有一个 Angular 函数,它在初始 URL 中查找“列表”参数,如果找到,就会出去获取信息。否则我想获得地理位置。如果存在 URL 参数,我不想获取地理位置。我使用的术语是否正确? constr
我读了很多关于锁定数据库、表和行的文章,但我想要较低的锁定,比如只锁定“操作”,我不知道如何调用它,假设我在 php 中有函数: function update_table() { //que
在我的多线程 mfc 应用程序中,m_view->SetScrollPos 处于阻塞状态并且所有应用程序都被卡住。 View 是在另一个线程中创建的,这是这种行为的原因吗? //SetScrollPo
FreeSwitch 软件在几天内运行良好(~3 - 5 天),然后由于 FreeSwitch 被阻止,新的来电请求被接受!!正在进行的调用继续他们的 session ,他们的调用似乎没有受到影响,但
我有一组按钮,当鼠标悬停在这些按钮上时,它们会改变颜色。这些的 CSS 以这种方式运行: #navsite ul li button { height: 60px; width: 60
由于某些原因,当我调用 WSARecvFrom 时,该函数在接收到某些内容之前不会返回。 _socket = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, N
我了解一些关于 Oracle 阻塞的知识——更新如何阻塞其他更新直到事务完成,写入者如何不阻塞读取者等。 我理解悲观和乐观锁定的概念,以及有关丢失更新等典型银行教科书示例。 我也理解 JDBC 事务隔
在两个代码点之间,我是否可以判断进程是否已被内核抢占,或者更确切地说,当时是否有任何其他代码在同一处理器上运行? //Point A some_type capture = some_capture(
这是我在 Oracle 的面试问题。 有一个堆栈,即使堆栈已满,push 操作也应该等到它完成,即使堆栈为空,pop 操作也应该等到它完成。 我们怎样才能做到这一点? 我的回答 让一个线程做push
我想知道是否有人可以告诉我如何有效地使用循环平铺/循环阻塞进行大型密集矩阵乘法。我正在用 1000x1000 矩阵做C = AB。我按照 Wikipedia 上的循环平铺示例进行操作,但使用平铺得到的
我正在阅读有关绿色线程的内容,并且能够理解这些线程是由 VM 或在运行时创建的,而不是由操作系统创建的,但我无法理解以下语句 When a green thread executes a blocki
我正在创建的 JavaScript API 具有以下结构: var engine = new Engine({ engineName: "TestEngine", engineHost
ChildWindow 是一个模态窗口,但它不会阻塞。有没有办法让它阻塞?我基本上想要一个 ShowDialog() 方法,该方法将调用 ChildWindow.Show() 但在用户关闭 Child
我需要一些关于如何调试 10.6 版本下的 Cocoa 并发问题的指导。我正在将“for”循环转换为使用 NSOperations,但大多数时候,代码只是在循环的某个时刻卡住。我可以在控制台中看到 N
我正在使用 ReportViewer 控件和自定义打印作业工作流程,这给我带来了一些问题。我的代码看起来有点像这样: ids.ForEach(delegate(Guid? guid)
我有以下成功复制文件的代码。但是,它有两个问题: progressBar.setValue() 之后的 System.out.println() 不会打印 0 到 100 之间的间隔(仅打印“0”直到
我是一名优秀的程序员,十分优秀!