使用http.Get()时出现死锁问题。

huangapple go评论81阅读模式
英文:

Dead block with http.Get()

问题

根据FuncOf文档:

调用任何需要事件循环的异步JavaScript API,比如fetch (http.Client),会导致立即死锁。因此,阻塞函数应该显式地启动一个新的goroutine。

所以,我写了下面的代码:

package main

import (
	"bytes"
	"fmt"
	"io"
	"net/http"
	"syscall/js"
)

func (db *DataBase) init(dataSet, table string) {
	var Ok, Err, Upgrade js.Func
	db.Request = Window.Get("indexedDB").Call("open", dataSet, 1)

	done := make(chan *bytes.Buffer)

	Upgrade = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		defer Upgrade.Release()
		db.Data = this.Get("result")

		fullUrlFile := "https://i.imgur.com/m1UIjW1.jpg"

		go func(fullUrlFile string) {
			var blob *bytes.Buffer

			r, e := http.Get(fullUrlFile)
			if e != nil {
				panic(e)
			}
			defer r.Body.Close()
			buildFileName()
			// Create blob
			var dest []byte

			blob = bytes.NewBuffer(dest)
			io.Copy(blob, r.Body)
			done <- blob
		}(fullUrlFile)

		blob := <-done

		Store := db.Data.Call("createObjectStore", table, map[string]interface{}{"keyPath": "id"})
		Store.Call("add", map[string]interface{}{"id": "00-03", "name": "Karam", "age": 19, "email": "kenny@planet.org", "image": blob})

		Window.Call("alert", "First record posted.")
		return nil
	})

	db.Request.Set("onupgradeneeded", Upgrade)
}

但是仍然出现应用程序退出的死锁错误!

fatal error: all goroutines are asleep - deadlock!
wasm_exec.js:51 
wasm_exec.js:51 goroutine 1 [chan receive]:
wasm_exec.js:51 main.main()
wasm_exec.js:51 	/home/hajsf/idb/main.go:24 +0x4
wasm_exec.js:51 
wasm_exec.js:51 goroutine 6 [chan receive]:
wasm_exec.js:51 main.(*DataBase).init.func1({{}, 0x7ff8000100000011, 0x410240}, {0x40ec80, 0x1, 0x1})
wasm_exec.js:51 	/home/hajsf/idb/initiate.go:57 +0xe
wasm_exec.js:51 syscall/js.handleEvent()
wasm_exec.js:51 	/usr/local/go/src/syscall/js/func.go:96 +0x27
wasm_exec.js:51 
wasm_exec.js:51 goroutine 7 [select]:
wasm_exec.js:51 net/http.(*Transport).RoundTrip(0x324e20, 0x492000)
wasm_exec.js:51 	/usr/local/go/src/net/http/roundtrip_js.go:170 +0x8d
wasm_exec.js:51 net/http.send(0x492000, {0xbe880, 0x324e20}, {0x0, 0x0, 0x0})
wasm_exec.js:51 	/usr/local/go/src/net/http/client.go:252 +0x8b
wasm_exec.js:51 net/http.(*Client).send(0x334a80, 0x492000, {0x0, 0x0, 0x0})
wasm_exec.js:51 	/usr/local/go/src/net/http/client.go:176 +0x11
wasm_exec.js:51 net/http.(*Client).do(0x334a80, 0x492000)
wasm_exec.js:51 	/usr/local/go/src/net/http/client.go:725 +0xb5
wasm_exec.js:51 net/http.(*Client).Do(...)
wasm_exec.js:51 	/usr/local/go/src/net/http/client.go:593
wasm_exec.js:51 net/http.(*Client).Get(0x334a80, {0x7546d, 0x1f})
wasm_exec.js:51 	/usr/local/go/src/net/http/client.go:480 +0xe
wasm_exec.js:51 net/http.Get(...)
wasm_exec.js:51 	/usr/local/go/src/net/http/client.go:449
wasm_exec.js:51 main.(*DataBase).init.func1.1(0x4360c0, {0x7546d, 0x1f})
wasm_exec.js:51 	/home/hajsf/idb/initiate.go:43 +0x4
wasm_exec.js:51 created by main.(*DataBase).init.func1
wasm_exec.js:51 	/home/hajsf/idb/initiate.go:40 +0xd
wasm_exec.js:151 exit code: 2
exit @ wasm_exec.js:151
runtime.wasmExit @ wasm_exec.js:275
$runtime.wasmExit @ main.wasm:0xe065d
$runtime.exit @ main.wasm:0xe048b
$runtime.fatalthrow.func1 @ main.wasm:0x7c1a2
$runtime.systemstack @ main.wasm:0xdd8f7
$runtime.fatalthrow @ main.wasm:0x7bff8
$runtime.throw @ main.wasm:0x7ba33
$runtime.checkdead @ main.wasm:0x9bcb8
$runtime.mput @ main.wasm:0x9e0f6
$runtime.stopm @ main.wasm:0x8ae91
$runtime.findrunnable @ main.wasm:0x8d33e
$runtime.schedule @ main.wasm:0x91430
$runtime.park_m @ main.wasm:0x9247f
$runtime.mcall @ main.wasm:0xdd88c
$runtime.gopark @ main.wasm:0x81740
$runtime.selectgo @ main.wasm:0xa5c4f
$net_http.__Transport_.RoundTrip @ main.wasm:0x3f3ae3
$wasm_pc_f_loop @ main.wasm:0xe0444
$wasm_export_resume @ main.wasm:0xe0425
_resume @ wasm_exec.js:588
(anonymous) @ wasm_exec.js:599
IndexedDB (async)
syscall/js.valueCall @ wasm_exec.js:399
$syscall_js.valueCall @ main.wasm:0x14799e
$syscall_js.Value.Call @ main.wasm:0x145065
$main.__DataBase_.init @ main.wasm:0x479c61
$main.init.0 @ main.wasm:0x47d181
$runtime.doInit @ main.wasm:0xa0e3d
$runtime.main @ main.wasm:0x80948
$wasm_pc_f_loop @ main.wasm:0xe0444
$wasm_export_run @ main.wasm:0xe0417
run @ wasm_exec.js:577
init @ wasm.js:7
await in init (async)
(anonymous) @ (index):20
(anonymous) @ (index):22
wasm_exec.js:586 Uncaught (in promise) Error: Go program has already exited
    at global.Go._resume (wasm_exec.js:586)
    at wasm_exec.js:599
_resume @ wasm_exec.js:586
(anonymous) @ wasm_exec.js:599
Promise.then (async)
syscall/js.valueCall @ wasm_exec.js:399
$syscall_js.valueCall @ main.wasm:0x14799e
$syscall_js.Value.Call @ main.wasm:0x145065
$net_http.__Transport_.RoundTrip @ main.wasm:0x3f3943
$wasm_pc_f_loop @ main.wasm:0xe0444
$wasm_export_resume @ main.wasm:0xe0425
_resume @ wasm_exec.js:588
(anonymous) @ wasm_exec.js:599
IndexedDB (async)
syscall/js.valueCall @ wasm_exec.js:399
$syscall_js.valueCall @ main.wasm:0x14799e
$syscall_js.Value.Call @ main.wasm:0x145065
$main.__DataBase_.init @ main.wasm:0x479c61
$main.init.0 @ main.wasm:0x47d181
$runtime.doInit @ main.wasm:0xa0e3d
$runtime.main @ main.wasm:0x80948
$wasm_pc_f_loop @ main.wasm:0xe0444
$wasm_export_run @ main.wasm:0xe0417
run @ wasm_exec.js:577
init @ wasm.js:7
await in init (async)
(anonymous) @ (index):20
(anonymous) @ (index):22
wasm_exec.js:586 Uncaught Error: Go program has already exited
    at global.Go._resume (wasm_exec.js:586)
    at IDBOpenDBRequest.<anonymous> (wasm_exec.js:599)

有什么想法吗?

英文:

As per FuncOf documentation:

> calling any async JavaScript API, which requires the event loop, like
> fetch (http.Client), will cause an immediate deadlock. Therefore a
> blocking function should explicitly start a new goroutine.

So, I wrote the below code:

package main

import (
	&quot;bytes&quot;
	&quot;fmt&quot;
	&quot;io&quot;
	&quot;net/http&quot;
	&quot;syscall/js&quot;
)
func (db *DataBase) init(dataSet, table string) {
	var Ok, Err, Upgrade js.Func
	db.Request = Window.Get(&quot;indexedDB&quot;).Call(&quot;open&quot;, dataSet, 1)

	done := make(chan *bytes.Buffer)

	Upgrade = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
		defer Upgrade.Release()
		db.Data = this.Get(&quot;result&quot;)

		fullUrlFile = &quot;https://i.imgur.com/m1UIjW1.jpg&quot;

		go func(fullUrlFile string) {
			var blob *bytes.Buffer

			r, e := http.Get(fullUrlFile)
			if e != nil {
				panic(e)
			}
			defer r.Body.Close()
			buildFileName()
			// Create blob
			var dest []byte

			blob = bytes.NewBuffer(dest)
			io.Copy(blob, r.Body)
			done &lt;- blob
		}(fullUrlFile)

		blob := &lt;-done

		Store := db.Data.Call(&quot;createObjectStore&quot;, table, map[string]interface{}{&quot;keyPath&quot;: &quot;id&quot;}) 
		Store.Call(&quot;add&quot;, map[string]interface{}{&quot;id&quot;: &quot;00-03&quot;, &quot;name&quot;: &quot;Karam&quot;, &quot;age&quot;: 19, &quot;email&quot;: &quot;kenny@planet.org&quot;, &quot;image&quot;: blob})

		Window.Call(&quot;alert&quot;, &quot;First record posted.&quot;)
		return nil
	})

   db.Request.Set(&quot;onupgradeneeded&quot;, Upgrade)
}

But still getting my app exiting with dead block!

fatal error: all goroutines are asleep - deadlock!
wasm_exec.js:51 
wasm_exec.js:51 goroutine 1 [chan receive]:
wasm_exec.js:51 main.main()
wasm_exec.js:51 	/home/hajsf/idb/main.go:24 +0x4
wasm_exec.js:51 
wasm_exec.js:51 goroutine 6 [chan receive]:
wasm_exec.js:51 main.(*DataBase).init.func1({{}, 0x7ff8000100000011, 0x410240}, {0x40ec80, 0x1, 0x1})
wasm_exec.js:51 	/home/hajsf/idb/initiate.go:57 +0xe
wasm_exec.js:51 syscall/js.handleEvent()
wasm_exec.js:51 	/usr/local/go/src/syscall/js/func.go:96 +0x27
wasm_exec.js:51 
wasm_exec.js:51 goroutine 7 [select]:
wasm_exec.js:51 net/http.(*Transport).RoundTrip(0x324e20, 0x492000)
wasm_exec.js:51 	/usr/local/go/src/net/http/roundtrip_js.go:170 +0x8d
wasm_exec.js:51 net/http.send(0x492000, {0xbe880, 0x324e20}, {0x0, 0x0, 0x0})
wasm_exec.js:51 	/usr/local/go/src/net/http/client.go:252 +0x8b
wasm_exec.js:51 net/http.(*Client).send(0x334a80, 0x492000, {0x0, 0x0, 0x0})
wasm_exec.js:51 	/usr/local/go/src/net/http/client.go:176 +0x11
wasm_exec.js:51 net/http.(*Client).do(0x334a80, 0x492000)
wasm_exec.js:51 	/usr/local/go/src/net/http/client.go:725 +0xb5
wasm_exec.js:51 net/http.(*Client).Do(...)
wasm_exec.js:51 	/usr/local/go/src/net/http/client.go:593
wasm_exec.js:51 net/http.(*Client).Get(0x334a80, {0x7546d, 0x1f})
wasm_exec.js:51 	/usr/local/go/src/net/http/client.go:480 +0xe
wasm_exec.js:51 net/http.Get(...)
wasm_exec.js:51 	/usr/local/go/src/net/http/client.go:449
wasm_exec.js:51 main.(*DataBase).init.func1.1(0x4360c0, {0x7546d, 0x1f})
wasm_exec.js:51 	/home/hajsf/idb/initiate.go:43 +0x4
wasm_exec.js:51 created by main.(*DataBase).init.func1
wasm_exec.js:51 	/home/hajsf/idb/initiate.go:40 +0xd
wasm_exec.js:151 exit code: 2
exit @ wasm_exec.js:151
runtime.wasmExit @ wasm_exec.js:275
$runtime.wasmExit @ main.wasm:0xe065d
$runtime.exit @ main.wasm:0xe048b
$runtime.fatalthrow.func1 @ main.wasm:0x7c1a2
$runtime.systemstack @ main.wasm:0xdd8f7
$runtime.fatalthrow @ main.wasm:0x7bff8
$runtime.throw @ main.wasm:0x7ba33
$runtime.checkdead @ main.wasm:0x9bcb8
$runtime.mput @ main.wasm:0x9e0f6
$runtime.stopm @ main.wasm:0x8ae91
$runtime.findrunnable @ main.wasm:0x8d33e
$runtime.schedule @ main.wasm:0x91430
$runtime.park_m @ main.wasm:0x9247f
$runtime.mcall @ main.wasm:0xdd88c
$runtime.gopark @ main.wasm:0x81740
$runtime.selectgo @ main.wasm:0xa5c4f
$net_http.__Transport_.RoundTrip @ main.wasm:0x3f3ae3
$wasm_pc_f_loop @ main.wasm:0xe0444
$wasm_export_resume @ main.wasm:0xe0425
_resume @ wasm_exec.js:588
(anonymous) @ wasm_exec.js:599
IndexedDB (async)
syscall/js.valueCall @ wasm_exec.js:399
$syscall_js.valueCall @ main.wasm:0x14799e
$syscall_js.Value.Call @ main.wasm:0x145065
$main.__DataBase_.init @ main.wasm:0x479c61
$main.init.0 @ main.wasm:0x47d181
$runtime.doInit @ main.wasm:0xa0e3d
$runtime.main @ main.wasm:0x80948
$wasm_pc_f_loop @ main.wasm:0xe0444
$wasm_export_run @ main.wasm:0xe0417
run @ wasm_exec.js:577
init @ wasm.js:7
await in init (async)
(anonymous) @ (index):20
(anonymous) @ (index):22
wasm_exec.js:586 Uncaught (in promise) Error: Go program has already exited
    at global.Go._resume (wasm_exec.js:586)
    at wasm_exec.js:599
_resume @ wasm_exec.js:586
(anonymous) @ wasm_exec.js:599
Promise.then (async)
syscall/js.valueCall @ wasm_exec.js:399
$syscall_js.valueCall @ main.wasm:0x14799e
$syscall_js.Value.Call @ main.wasm:0x145065
$net_http.__Transport_.RoundTrip @ main.wasm:0x3f3943
$wasm_pc_f_loop @ main.wasm:0xe0444
$wasm_export_resume @ main.wasm:0xe0425
_resume @ wasm_exec.js:588
(anonymous) @ wasm_exec.js:599
IndexedDB (async)
syscall/js.valueCall @ wasm_exec.js:399
$syscall_js.valueCall @ main.wasm:0x14799e
$syscall_js.Value.Call @ main.wasm:0x145065
$main.__DataBase_.init @ main.wasm:0x479c61
$main.init.0 @ main.wasm:0x47d181
$runtime.doInit @ main.wasm:0xa0e3d
$runtime.main @ main.wasm:0x80948
$wasm_pc_f_loop @ main.wasm:0xe0444
$wasm_export_run @ main.wasm:0xe0417
run @ wasm_exec.js:577
init @ wasm.js:7
await in init (async)
(anonymous) @ (index):20
(anonymous) @ (index):22
wasm_exec.js:586 Uncaught Error: Go program has already exited
    at global.Go._resume (wasm_exec.js:586)
    at IDBOpenDBRequest.&lt;anonymous&gt; (wasm_exec.js:599)

Any thought?

答案1

得分: 0

我找到了,goroutine 应该覆盖整个函数范围,像这样:

js.FuncOf(func(this js.Value, args []js.Value) interface{} {
  go func() {
    [...]
    someBlockingFunction()
    [...]
  }()
})
英文:

I found it, the goroutine should be covering the full function scope, like:

js.FuncOf(func(this js.Value, args []js.Value) interface{} {
  go func() {
    [...]
    someBlockingFunction()
    [...]
  }()
})

huangapple
  • 本文由 发表于 2021年11月18日 16:55:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/70016981.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定