2017-11-22 9 views
0

私が作業しているアップロードプログラムがあり、問題が発生しています。私は大きなファイルに部品をアップロードするルーチンを持っています。基本的には、ファイルを100MBのチャンクに分割し、configで指定した同時プロセスの量に応じて同時にアップロードします。スライスバイトのゴルーチンがハングアップする

問題は、ファイルを読み込んでmake([]バイト、100000000)がアップロードされるようにバッファを作成したときです...ただし、それが実行ルーチンにある場合のみです。 (アップロードの計算を簡略化するために100000000を使用しています)

ここは例です。

これは動作します:https://play.golang.org/p/tkn8JVir9S

package main 

import (
    "fmt" 
) 

func main() { 
    buffer := make([]byte, 100000000) 
    fmt.Println(len(buffer)) 
} 

これにはない:https://play.golang.org/p/H8626OLpqQ

package 

main 

import (
    "fmt" 
) 

func main() { 
    go createBuffer() 
    for { 
    } 

} 

func createBuffer() { 
    buffer := make([]byte, 100000000) 
    fmt.Println(len(buffer)) 
} 

それはちょうどハング...私は行くルーチンのメモリ制約があるかどうかわかりませんか?私は何を見つけることができたのか、何も見つけられなかったことを研究してみました。いかなる考えも認められるだろう。

編集:フィードバックいただきありがとうございます。私は本当の問題をとてもうまく説明しなかったと言い、次回は全体像をより多く提供しようとします。私は、新しいファイルを処理するために自分のゴルーチンを準備しておくために、チャンネルを使ってブロックしました。これは、サードパーティにアップロードするDRバックアップのためのもので、大きなファイルを100MBのチャンクに分割する必要があります。私は自分のプログラムの性質についてより明確にすべきだったと思います。

+6

あなたは、あなたのプログラムでビジーループを持っています。空のループを使う理由は決してありません。理由なくCPUの100%を消費しており、最終的にはランタイムをブロックします。 – JimB

+0

for {}の代わりに 'select {}'を使うようにしてください。最良の方法ではありません(実行ルーチンが終了したときにチェックするためにチャネルを使用する必要があります)が、テスト目的では問題ありません。 – ajnavarro

+0

goroutineにバイトスライスを割り当てることは、https://play.golang.org/p/8QawOUTFybのようにうまくいきます.JimBが既に指摘したように、あなたの例の問題はforループです。 – mkopriva

答えて

1

コードに無限ループが存在するため、このプログラムがハングします。このようにコードを実行して自分自身に証明してみてください。 goroutineは、ぶら下がりを引き起こしているものではありません。

func main() { 
    for { 
    } 
} 

あなただけfmt.Println(..)プリントを見たい場合は、その後、私はtime.Sleepコールまたは類似したお勧めします。

多くのゴルーチンが完了するのを待っている場合は、その正確な質問にthis excellent answerをお勧めします。 func Gosched

func Gosched() 

Gosched

import "runtime" 

Package runtime

+0

私は、ファイルを処理しているゴルーチンを持っていて、開いたままにして、開いたままにしておく必要があります。私が抱えている問題は、デーモンとしてアプリケーションを実行していることで、これがこの問題を引き起こしています。 – MattA

+0

[この投稿](https://stackoverflow.com/questions/23736046/how-to-create-a-daemon-process-in-golang)は、デーモンを作りたい場合には開始するのに適しています。主な問題は、CPUサイクルを浪費しないように、ビジーウェイトループを持たないことです。 –

0

他のゴルーチンが実行できるように、プロセッサが得られます。 は現在のゴルーチンを中断しないので、実行は自動的に に戻ります。


あなたは(for {}100MB)奇妙な何かをするとき、あなたは奇妙な結果を得ることができます。合理的な何かをしなさい例えば、出力

package main 

import (
    "fmt" 
    "runtime" 
) 

func main() { 
    go createBuffer() 
    for { 
     runtime.Gosched() 
    } 
} 

func createBuffer() { 
    buffer := make([]byte, 100000000) 
    fmt.Println(len(buffer)) 
} 

100000000 
^Csignal: interrupt 
+0

さて、いくつかのファイルを処理しているいくつかの実行中のルーチンがありますが、そのうちのいくつかは、同時プロセスを決定するためにconfigを使用します。問題は、HTTPポスト経由で送信するためにファイルを100MBのチャックにスライスする必要があるため、100MBが奇妙ではないということです。私のチャンネルを追加して完成したファイルを返す理由については、forループのところでこの問題は消えました。 – MattA

+0

@MattA:あなたの例は非常に工夫されています。あなたの実際のケースは異なっています。また、チャンクごとに100MBのメモリを使用して100MBのチャンクを同時に送信することは非効率的です。 10,000人のユーザーをサポートするにはどれくらいのメモリが必要ですか?より良い戦略が必要です。 Googleは内部的に[dl.google.comが現在提供している](https://groups.google.com/forum/#!topic/golang-nuts/BNUNbKSypE0)と[dl.google.com:Powered by Go](https://talks.golang.org/2013/oscon-dl.slide#1)。 – peterSO

+0

私は同意する、私は正確な問題と私がそれをやっていた理由をもう少し明示されている必要があります。私はそれの背後にある理由についてもっと興味がありました。そして今、私はそれが理にかなった反応を見ています。私は実際にブロックするチャンネルを持つ必要があり、エラーまでgoroutinesを続行させます。非効率性に関しては、これはDRバックアッププロバイダへのアップロードユーティリティであるため、ユーザーはいません。設定ファイルでは最大並列プロセスを定義することができます。これはメモリ消費の上限です。 DR APIを使用するには、大きなファイルをチャンクに分割してPOST本体に送信する必要があります。 – MattA

関連する問題