- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
在我添加了我正在使用的一小部分文件 (7 GB) 并尝试运行该程序后,我可以看到:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
/media/developer/golang/manual/examples/sp/v2/sp.v2.go:71 +0x4a9
exit status 2
我是 GO 的新手,所以如果我的问题真的很简单,我很抱歉。
我正在尝试流式传输 xml
文件、拆分文档,然后在不同的 GO 例程中解析它们。
我正在使用的 XML 文件示例:
<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="CGImap 0.0.2">
<relation id="56688" user="kmvar" uid="56190" visible="true" version="28" changeset="6947637" timestamp="2011-01-12T14:23:49Z">
<member type="node" ref="294942404" role=""/>
<member type="node" ref="364933006" role=""/>
<tag k="name" v="Küstenbus Linie 123"/>
<tag k="network" v="VVW"/>
<tag k="route" v="bus"/>
<tag k="type" v="route"/>
</relation>
<relation id="98367" user="jdifh" uid="92834" visible="true" version="28" changeset="6947637" timestamp="2011-01-12T14:23:49Z">
<member type="node" ref="294942404" role=""/>
<member type="way" ref="4579143" role=""/>
<member type="node" ref="249673494" role=""/>
<tag k="name" v="Küstenbus Linie 123"/>
<tag k="network" v="VVW"/>
<tag k="operator" v="Regionalverkehr Küste"/>
<tag k="ref" v="123"/>
</relation>
<relation id="72947" user="schsu" uid="92374" visible="true" version="28" changeset="6947637" timestamp="2011-01-12T14:23:49Z">
<member type="node" ref="294942404" role=""/>
<tag k="name" v="Küstenbus Linie 123"/>
<tag k="type" v="route"/>
</relation>
<relation id="93742" user="doiff" uid="61731" visible="true" version="28" changeset="6947637" timestamp="2011-01-12T14:23:49Z">
<member type="node" ref="294942404" role=""/>
<member type="node" ref="364933006" role=""/>
<tag k="route" v="bus"/>
<tag k="type" v="route"/>
</relation>
</osm>
我有这段代码:
package main
import (
"encoding/xml"
"bufio"
"fmt"
"os"
"io"
)
type RS struct {
I string `xml:"id,attr"`
M []struct {
I string `xml:"ref,attr"`
T string `xml:"type,attr"`
R string `xml:"role,attr"`
} `xml:"member"`
T []struct {
K string `xml:"k,attr"`
V string `xml:"v,attr"`
} `xml:"tag"`
}
func main() {
p1D, err := os.Open("/media/developer/Transcend/osm/xml/relations.xml")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer p1D.Close()
reader := bufio.NewReader(p1D)
var count int32
var element string
channel := make(chan RS) // channel
for {
p2Rc, err := reader.ReadSlice('\n')
if err != nil {
if err == io.EOF {
break
} else {
fmt.Println(err)
os.Exit(1)
}
}
var p2Rs = string(p2Rc)
if p2Rc[2] == 114 {
count++
if (count != 1) {
go parseRelation(element, channel)
}
element = ""
element += p2Rs
} else {
element += p2Rs
}
}
for i := 0; i < 5973974; i++ {
fmt.Println(<- channel)
}
}
func parseRelation(p1E string, channel chan RS) {
var rs RS
xml.Unmarshal([]byte(p1E), &rs)
channel <- rs
}
它应该打印每个结构,但我什么也没看到。程序只是挂起。
我测试了 streamer 和 splitter(只是在将消息发送到 channel 之前在函数 parseRelation 中添加了 fmt.Println(rs)
)。我可以看到结构。因此,问题在于发送和接收消息。
我不知道如何解决这个问题。尝试更改 channel 中消息的类型(从 RS
到 string
)并且每次只发送一个字符串。但它也没有帮助(我什么也看不到)
最佳答案
首先,让我们解决这个问题:您不能逐行解析 XML。您很幸运,您的文件恰好是每行一个标签,但这不能想当然。您必须解析整个 XML 文档。
通过逐行处理,你试图推 <tag>
和 <member>
进入为 <relation>
设计的结构中.相反,使用 xml.NewDecoder
并让它为您处理文件。
package main
import (
"encoding/xml"
"fmt"
"os"
"log"
)
type Osm struct {
XMLName xml.Name `xml:"osm"`
Relations []Relation `xml:"relation"`
}
type Relation struct {
XMLName xml.Name `xml:"relation"`
ID string `xml:"id,attr"`
User string `xml:"user,attr"`
Uid string `xml:"uid,attr"`
Members []Member `xml:"member"`
Tags []Tag `xml:"tag"`
}
type Member struct {
XMLName xml.Name `xml:"member"`
Ref string `xml:"ref,attr"`
Type string `xml:"type,attr"`
Role string `xml:"role,attr"`
}
type Tag struct {
XMLName xml.Name `xml:"tag"`
Key string `xml:"k,attr"`
Value string `xml:"v,attr"`
}
func main() {
reader, err := os.Open("test.xml")
if err != nil {
log.Fatal(err)
}
defer reader.Close()
decoder := xml.NewDecoder(reader)
osm := &Osm{}
err = decoder.Decode(&osm)
if err != nil {
log.Fatal(err)
}
fmt.Println(osm)
}
Osm
其他结构类似于您期望的 XML 模式。 decoder.Decode(&osm)
应用该模式。
如果您只想提取部分 XML,see the answers to How to extract part of an XML file as a string? .
答案的其余部分将仅涵盖 channel 和协程的使用。 XML 部分将被删除。
如果添加一些调试语句,您会发现 parseRelation
从未被调用,这意味着 channel
是空的 fmt.Println(<- channel)
坐在那里等待一个永远不会关闭的空 channel 。因此,一旦您完成处理,请关闭 channel 。
for {
p2Rc, err := reader.ReadSlice('\n')
...
}
close(channel)
现在我们得到 { [] []}
5973974次。
for i := 0; i < 5973974; i++ {
fmt.Println(<- channel)
}
尝试从 channel 读取 5973974 次。这违背了 channel 的意义。相反,read from the channel using range
.
for thing := range channel {
fmt.Println(thing)
}
现在至少它完成了!
但是有一个新问题。如果它真的找到了东西,比如你改变了 if p2Rc[2] == 114 {
至 if p2Rc[2] == 32 {
,你会得到一个 panic: send on closed channel
.这是因为 parseRelation
与阅读器并行运行,可能会在主要阅读代码完成并关闭 channel 后尝试写入。在关闭 channel 之前,您必须确保使用该 channel 的每个人都已完成。
要解决此问题,需要进行相当大的重新设计。
这是一个简单程序的示例,它从文件中读取行,将它们放入 channel ,然后让工作人员从该 channel 读取。
func main() {
reader, err := os.Open("test.xml")
if err != nil {
log.Fatal(err)
}
defer reader.Close()
// Use the simpler bufio.Scanner
scanner := bufio.NewScanner(reader)
// A buffered channel for input
lines := make(chan string, 10)
// Work on the lines
go func() {
for line := range lines {
fmt.Println(line)
}
}()
// Read lines into the channel
for scanner.Scan() {
lines <- scanner.Text()
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
// When main exits, channels gracefully close.
}
这很好用因为 main
是特殊的并在退出时清理 channel 。但是,如果读者和作者都是 goroutines 怎么办?
// A buffered channel for input
lines := make(chan string, 10)
// Work on the lines
go func() {
for line := range lines {
fmt.Println(line)
}
}()
// Read lines into the channel
go func() {
for scanner.Scan() {
lines <- scanner.Text()
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
}()
空的。 main
在 goroutines 可以完成他们的工作之前退出并关闭 channel 。我们需要一种方法让 main
知道要等到处理完成。有几种方法可以做到这一点。一个是 another channel to synchronize processing .
// A buffered channel for input
lines := make(chan string, 10)
// A channel for main to wait for
done := make(chan bool, 1)
// Work on the lines
go func() {
for line := range lines {
fmt.Println(line)
}
// Indicate the worker is done
done <- true
}()
// Read lines into the channel
go func() {
// Explicitly close `lines` when we're done so the workers can finish
defer close(lines)
for scanner.Scan() {
lines <- scanner.Text()
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
}()
// main will wait until there's something to read from `done`
<-done
现在main
将触发 reader 和 worker goroutines 并缓冲等待 done
上的东西.读者填写lines
直到它完成阅读然后关闭它。同时,工作人员将从 lines
读取并写信给done
一旦完成阅读。
另一种选择是使用 sync.WaitGroup .
// A buffered channel for input
lines := make(chan string, 10)
var wg sync.WaitGroup
// Note that there is one more thing to wait for
wg.Add(1)
go func() {
// Tell the WaitGroup we're done
defer wg.Done()
for line := range lines {
fmt.Println(line)
}
}()
// Read lines into the channel
go func() {
defer close(lines)
for scanner.Scan() {
lines <- scanner.Text()
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
}()
// Wait until everything in the WaitGroup is done
wg.Wait()
和以前一样,main
启动 reader 和 worker goroutines,但现在它在启动 worker 之前将 1 添加到 WaitGroup。然后它一直等到 wg.Wait()
返回。阅读器与以前一样工作,关闭 lines
channel 完成后。 worker 现在调用 wg.Done()
当它完成递减 WaitGroup 的计数并允许 wg.Wait()
时返回。
每种技术都有优点和缺点。 done
更灵活,链条更好,如果你能把头绕在它身上会更安全。 WaitGroups 更简单,更容易让您头脑清醒,但要求每个 goroutine 共享一个变量。
如果我们想添加到这个处理链中,我们可以这样做。假设我们有一个读取行的 goroutine,一个在 XML 元素中处理它们,一个对元素执行某些操作。
// A buffered channel for input
lines := make(chan []byte, 10)
elements := make(chan *RS)
var wg sync.WaitGroup
// Worker goroutine, turn lines into RS structs
wg.Add(1)
go func() {
defer wg.Done()
defer close(elements)
for line := range lines {
if line[2] == 32 {
fmt.Println("Begin")
fmt.Println(string(line))
fmt.Println("End")
rs := &RS{}
xml.Unmarshal(line, &rs)
elements <- rs
}
}
}()
// File reader
go func() {
defer close(lines)
for scanner.Scan() {
lines <- scanner.Bytes()
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
}()
// Element reader
wg.Add(1)
go func() {
defer wg.Done()
for element := range elements {
fmt.Println(element)
}
}()
wg.Wait()
这会产生空结构,因为您正试图将单独的 XML 行插入表示完整 <relationship>
的结构中。标签。但它演示了如何向链中添加更多 worker 。
关于go - 没有收到来自 channel 的消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52137847/
我一直在读到,如果一个集合“被释放”,它也会释放它的所有对象。另一方面,我还读到,一旦集合被释放,集合就会释放它的对象。 但最后一件事可能并不总是发生,正如苹果所说。系统决定是否取消分配。在大多数情况
我有一个客户端-服务器应用程序,它使用 WCF 进行通信,并使用 NetDataContractSerializer 序列化对象图。 由于服务器和客户端之间传输了大量数据,因此我尝试通过微调数据成员的
我需要有关 JMS 队列和消息处理的帮助。 我有一个场景,需要针对特定属性组同步处理消息,但可以在不同属性组之间同时处理消息。 我了解了特定于每个属性的消息组和队列的一些知识。我的想法是,我想针对
我最近开始使用 C++,并且有一种强烈的冲动 #define print(msg) std::cout void print(T const& msg) { std::cout void
我已经为使用 JGroups 编写了简单的测试。有两个像这样的简单应用程序 import org.jgroups.*; import org.jgroups.conf.ConfiguratorFact
这个问题在这里已经有了答案: Firebase messaging is not supported in your browser how to solve this? (3 个回答) 7 个月前关
在我的 C# 控制台应用程序中,我正在尝试更新 CRM 2016 中的帐户。IsFaulted 不断返回 true。当我向下钻取时它返回的错误消息如下: EntityState must be set
我正在尝试通过 tcp 将以下 json 写入 graylog 服务器: {"facility":"GELF","file":"","full_message":"Test Message Tcp",
我正在使用 Django 的消息框架来指示成功的操作和失败的操作。 如何排除帐户登录和注销消息?目前,登录后登陆页面显示 已成功登录为“用户名”。我不希望显示此消息,但应显示所有其他成功消息。我的尝试
我通过编写禁用qDebug()消息 CONFIG(release, debug|release):DEFINES += QT_NO_DEBUG_OUTPUT 在.pro文件中。这很好。我想知道是否可以
我正在使用 ThrottleRequest 来限制登录尝试。 在 Kendler.php 我有 'throttle' => \Illuminate\Routing\Middleware\Throttl
我有一个脚本,它通过die引发异常。捕获异常时,我想输出不附加位置信息的消息。 该脚本: #! /usr/bin/perl -w use strict; eval { die "My erro
允许的消息类型有哪些(字符串、字节、整数等)? 消息的最大大小是多少? 队列和交换器的最大数量是多少? 最佳答案 理论上任何东西都可以作为消息存储/发送。实际上您不想在队列上存储任何内容。如果队列大部
基本上,我正在尝试创建一个简单的 GUI 来与 Robocopy 一起使用。我正在使用进程打开 Robocopy 并将输出重定向到文本框,如下所示: With MyProcess.StartI
我想将进入 MQ 队列的消息记录到数据库/文件或其他日志队列,并且我无法修改现有代码。是否有任何方法可以实现某种类似于 HTTP 嗅探器的消息记录实用程序?或者也许 MQ 有一些内置的功能来记录消息?
我得到了一个带有 single_selection 数据表和一个命令按钮的页面。命令按钮调用一个 bean 方法来验证是否进行了选择。如果不是,它应该显示一条消息警告用户。如果进行了选择,它将导航到另
我知道 MSVC 可以通过 pragma 消息做到这一点 -> http://support.microsoft.com/kb/155196 gcc 是否有办法打印用户创建的警告或消息? (我找不到谷
当存在大量节点或二进制数据时, native Erlang 消息能否提供合理的性能? 情况 1:有一个大约 50-200 台机器的动态池(erlang 节点)。它在不断变化,每 10 分钟大约添加或删
我想知道如何在用户登录后显示“欢迎用户,您已登录”的问候消息,并且该消息应在 5 秒内消失。 该消息将在用户成功登录后显示一次,但在同一 session 期间连续访问主页时不会再次显示。因为我在 ho
如果我仅使用Welcome消息,我的代码可以正常工作,但是当打印p->client_name指针时,消息不居中。 所以我的问题是如何将消息和客户端名称居中,就像它是一条消息一样。为什么它目前仅将消
我是一名优秀的程序员,十分优秀!