2017-01-02 29 views
1

DBから別のデータベースに大量のデータを移行するスクリプトを作成して正常に動作しましたが、現在はゴーリンを使用して同時DB呼び出しを使用してスクリプトを高速化します。ちょうどprocessBatch(offset)の代わりにgo processBatch(offset)を呼び出す変更を行ったので、いくつかのゴルーチンが開始されていますが、スクリプトはほぼ即座に終了し、実際には何も行われません。また、起動したゴルーチンの数は、スクリプトを呼び出すたびに変わります。エラーはありません(私が見ることができます)。ゴルーチンのDBコールでエラーが発生してもエラーが発生しない

私はまだgoroutinesとGoに一般的なので、私が間違っているかもしれないことについての指針は非常に高く評価されています。私は変更なしで正常に動作するので、並行処理やDBアクセスに関係しない以下のコードからすべてのロジックを削除しました。私はまた、その行の下の何も実行されないので、失敗したと思うところでコメントを残しました(Printは出力しません)。私もsync.WaitGroupを使ってDBコールをずらしてみましたが、何も変えていないようです。 NADHはコメントで述べたようにmain関数が終了すると、プログラムが終了したために

var (
    legacyDB  *sql.DB 
    v2DB   *sql.DB 
) 

func main() { 

    var total, loops int 
    var err error 

    legacyDB, err = sql.Open("mysql", "...") 
    if err != nil { 
     panic(err) 
    } 
    defer legacyDB.Close() 

    v2DB, err = sql.Open("mysql", "...") 
    if err != nil { 
     panic(err) 
    } 
    defer v2DB.Close() 

    err = legacyDB.QueryRow("SELECT count(*) FROM users").Scan(&total) 
    checkErr(err) 

    loops = int(math.Ceil(float64(total)/float64(batchsize))) 

    fmt.Println("Total: " + strconv.Itoa(total)) 
    fmt.Println("Loops: " + strconv.Itoa(loops)) 

    for i := 0; i < loops; i++ { 
     offset := i * batchsize 

     go processBatch(offset) 
    } 

    legacyDB.Close() 
    v2DB.Close() 
} 

func processBatch(offset int) { 

    query := namedParameterQuery.NewNamedParameterQuery(` 
     SELECT ... 
     LIMIT :offset,:batchsize 
    `) 
    query.SetValue(...) 

    rows, err := legacyDB.Query(query.GetParsedQuery(), (query.GetParsedParameters())...) 
    // nothing after this line gets done (Println here does not show output) 
    checkErr(err) 
    defer rows.Close() 

    .... 

    var m runtime.MemStats 
    runtime.ReadMemStats(&m) 
    log.Printf("\nAlloc = %v\nTotalAlloc = %v\nSys = %v\nNumGC = %v\n\n", m.Alloc/1024/1024, m.TotalAlloc/1024/1024, m.Sys/1024/1024, m.NumGC) 
} 

func checkErr(err error) { 
    if err != nil { 
     panic(err) 
    } 
} 
+2

あなたは 'processBatch()'ルーチンを産卵していると

fmt.Println("Total: " + strconv.Itoa(total)) fmt.Println("Loops: " + strconv.Itoa(loops)) for i := 0; i < loops; i++ { offset := i * batchsize go processBatch(offset) } 

を交換するように見えるが、あなたの 'メインのでしょう'彼らが終わり、ただ終わるのを待たずに。 'sync.WaitGroup'を使って' main() 'がすべてのゴルーチンが終了するのを待つことができます。 – Nadh

答えて

2

、それが実行している他のゴルーチンがまだあるかどうかにかかわらず、だろう。これを修正するには、* sync.WaitGroupで十分です。 WaitGroupは、複数の同時操作がある場合に使用され、すべて完了するまで待機します。ドキュメントはhttps://golang.org/pkg/sync/#WaitGroupにあります。

グローバル変数を使用せずに、あなたのプログラムの実装例では)(

fmt.Println("Total: " + strconv.Itoa(total)) 
fmt.Println("Loops: " + strconv.Itoa(loops)) 

wg := new(sync.WaitGroup) 
wg.Add(loops) 

for i := 0; i < loops; i++ { 
    offset := i * batchsize 

    go func(offset int) { 
     defer wg.Done() 
     processBatch(offset) 
    }(offset) 
} 

wg.Wait() 
+0

申し訳ありませんが、以前私がWaitGroupを試してみたところで、すでにこのソリューションに近づいていたようですが、実際にどのように/どこで使用するのかを実際には理解できませんでした。これは、多くのおかげで、助けて! – sekl

関連する問題