2017-02-22 10 views
1

У меня есть следующая часть кода, которая не записывает никаких данных в файл log.txt. Я не понимаю, почему? Это не должно быть проблемой синхронизации, потому что я закрываю файл перед запуском любой процедуры go и открываю/закрываю файл внутри каждой процедуры.Golang: почему следующий фрагмент кода не записывается в файл?

package main 

import (
    "fmt" 
    "runtime" 
    "os" 
    "time" 
) 

func main() { 
    runtime.GOMAXPROCS(4) 

    f, _ := os.Create("./log.txt") 
    f.Close() 

    logCh := make(chan string, 50) 

    go func() { 
     for { 
      msg, ok := <- logCh 
      if ok { 
       logTime := time.Now().Format(time.RFC3339) 

       f, _ := os.OpenFile("./log.txt", os.O_APPEND, os.ModeAppend) 

       f.WriteString(logTime + " - " + msg) 

       f.Close() 

      } else { 
       break 
      } 
     } 
    }() 


    for i:=1; i < 10;i++ { 
     for j:=1; j<10;j++ { 
      go func(i, j int) { 
       msg := fmt.Sprintf("%d + %d = %d\n", i, j, i+j) 
       logCh <- msg 
       fmt.Print(msg) 
      }(i, j) 
     } 
    } 


    //fmt.Scanln() 
} 

ответ

1

Для этого вам нужно подождать, пока ваш канал не будет пуст. В этом случае вам также не нужен буферный канал. Используйте WaitGroup

Во-вторых, открытие и закрытие файла в каждой горуте, игнорируя ошибку, является актуальной проблемой. Вам не нужно открывать и закрывать файл каждый раз. Открывать один раз, синхронизировать после записи.

Это работает:

пакет главный

import (
    "fmt" 
    "os" 
    "runtime" 
    "sync" 
    "time" 
) 

func main() { 
    runtime.GOMAXPROCS(4) 

    f, _ := os.Create("./log.txt") 
    defer f.Close() 

    logCh := make(chan string) 
    var wg sync.WaitGroup 

    for i := 1; i < 10; i++ { 
     for j := 1; j < 10; j++ { 
      wg.Add(1) 
      go func(i, j int) { 
       defer wg.Done() 
       msg := fmt.Sprintf("%d + %d = %d\n", i, j, i+j) 
       logCh <- msg 
       fmt.Print(msg) 

      }(i, j) 
     } 
    } 

    go func() { 
     for { 
      msg, ok := <-logCh 
      if ok { 
       logTime := time.Now().Format(time.RFC3339) 

       f.WriteString(logTime + " - " + msg) 
       f.Sync() 

      } else { 
       break 
      } 
     } 
    }() 

    wg.Wait() 

    //fmt.Scanln() 
} 

Там также некоторые дополнительные данные в this question

+0

Да, я сделал это было. Не делайте близких сразу после создания и используйте один и тот же fileDescriptior внутри каждого goroutine для записи в файлах. Да - в этом случае он будет работать без WaitGroup. Но почему это не работает в исходном примере - файлы создаются и закрываются, прежде чем запускается какой-либо канал или goroutine. И я открываю/закрываю файлы внутри каждого goroutine. Но файлы все еще пусты. Зачем ? – PARUS

+0

Буферизованные каналы не блокируются. Ваш основной() выйдет быстрее. – favoretti

2

два очевидных недостатков:

  1. главная программа не ждать, пока другие goroutines, когда основная рутина возвращается, программа завершается, это почему log.txt пуст. sync.WaitGroup может быть полезно.

  2. msg, ok := <- logCh, ok только false когда logCh закрыт и пуст. И вы не звоните close(logCh).

+0

Но файл, созданный и закрытый внутри основной процедуры перед тем, как запускается какой-либо другой goroutine, я открываю и закрываю файлы внутри каждой основной процедуры, но файлы становятся пустыми. – PARUS

+0

@PARUS что вы имеете в виду «Я открываю и закрываю файлы внутри каждой основной программы»? 'WriteString' будет выполняться только при получении сообщения' logCh'. но до этого основная функция закончилась. – zzn

+0

>> если logCh получает сообщение. но до этого основная функция закончилась. Извините, в коде выше вам нужно раскомментировать следующий //fmt.Scanln(), а основная функция все еще выполняется. – PARUS