Втора задача

  1. Публикувана е втората задача за домашно. Ще ви е много полезно предварително да прочетете този гайд. Условието, както и малък тест, могат да бъдат намерени и в github хранилището ни.

    Тук можете да ни питате ако има нещо неясно по условието.

  2. Въпрос: в кода на условието на домашното следното:

    // Print the first message now just because we can

    fmt.Println(<-orderedLog)

    принтира само първото съобщение:

    1 test message 1 in first

    а накрая: // Print all the rest of the messages

    for logEntry := range orderedLog { fmt.Println(logEntry) }

    принтира целия, т.е. не трябва ли пак да се принтира първото съобщение и накрая на конзолата то да е изведено 2 пъти?

  3. @Ива,

    Веднъж след като прочетеш нещо от канала, то вече не се намира там. Представи си, че от двете страни се подават данни. Те не се задържат вътре в самия канал (ако не е буфериран), но излезе ли нещо от него - то вече не може да бъде прочетено отново.

  4. EDIT: Разбрах причината. Получаваше се blocking, защото нямаше какво да консумира съобщенията. Move along.

    Натъкнах се на проблем с каналите. Предполагам проблемът е очевиден, но се боря от известно време с него и не ми е ясно какво правя грешно. Абстрахирайки се от условието на домашното, ето какво представлява проблема ми:

    func main() {
      channel := make(chan int)
    
      go func() {
        channel <- 1
        channel <- 2
        close(channel)
      }()
    
      for val := range channel {
        fmt.Printf("%d\n", val)
      }
    }
    

    Това си работи както предполагаме. Но не разбирам защо следния код ми хвърля deadlock:

    func main() {
      channel := make(chan int)
      channel <- 1
      channel <- 2
      close(channel)
    
      go func() {
        for val := range channel {
          fmt.Printf("%d\n", val)
        }
      }()
    }
    
  5. Аз също имам подобен проблем ... Каквото и да направя хвърля deadlock. В случая ми хвърля при извикването на функцията и при начало на обхождане на даден канал във функцията ... На какво може да се дължи ?

  6. Вероятно се опитваш да пишеш в небуфериран канал и няма кой да го прочете или се опитваш да четеш от канал, но никой не пише в него. Начертай си различните горутини (вкл. основната, която вика OrderedLogDrainer()) и как си взаимодействат (каналите) и вероятно сам ще си отговориш на въпроса.

  7. as a rule of thumb:

    • Не се опитвайте да четете и пишете в един и същ (небуфериран) канал в една горутина. Не, че няма как да се получи, но ще си спестите главоболия за момента.

    • Отделно, ако стартирате друга горутина да чета/пише в канал - то стартирайте я преди да сте се опитали да пишете/четете от главната.

      • Окей, но защо? - Защото ако блокирате на писането, то тази горутина, която трябва да чете няма да се стартира.
  8. @Антоан, програмата ти deadlock-ва като стигне реда

    channel <- 1
    

    защото никой не чете от него. Ако извикаш ламда функцията преди да пишеш в channel всичко ще е както си трябва.

    П.С. Извинявам се, ноо като писах това, все още не беше излезнал отговорът на Недялко ^^

  9. Аa, тъй като доста време никой не качи тестове, реших аз да споделя моите ^^

    (edit: промених тестовете да ползват wait groups вместо да е ръчно със семафори, защото е маалко по-красиво и добавих допълнителен тестов случай)

  10. Имам проблем с подредбата на канали(относно въпроса с поредния номер). Прерових Гугъл, изгледах и лекцията на Роб Пайк (там само спомена за това), но не мога да намеря отговор ...Как мога да кажа на даден канал " Пиши първо от first,като се затвори пиши от second" и т.н. ?

  11. Пример:

    logs := make(chan (chan string))
    orderedLog := OrderedLogDrainer(logs)
    
    first := make(chan string)
    logs <- first
    second := make(chan string)
    logs <- second
    
    first <- "test message 1 in first"
    second <- "test message 1 in second"
    second <- "test message 2 in second"
    // Print two messages
    // What we get ?!?
    fmt.Println(<-orderedLog)
    fmt.Println(<-orderedLog)
    
    first <- "test message 4 in first"
    close(first)
    second <- "test message 3 in second"
    close(logs)
    
    second <- "test message 4 in second"
    close(second)
    
    // Print all the rest of the messages
    for logEntry := range orderedLog {
        fmt.Println(logEntry)
    }
    

    Какво се очаква да изведа като изход и въобще това валиден пример ли е? На мен ми изглежда като невъзможен пример.

    Причината за това е, че четем 2 стойности от orderedLog докато сме записали само 1 във first и не сме го затворили.

  12. Не, че е от особено значение в подобна задача, но fmt функциите не са много бързи. Съответно за прости неща като текущия случай или супер критични участъци от програмата предпочитам да използвам алтернативи. Може да си пуснеш следната програма с go run и сам да провериш разликите в скоростта:

    package main
    
    import (
        "fmt"
        "strconv"
        "testing"
    )
    
    func main() {
    
        fmt.Println("concatStrConv ", testing.Benchmark(func(b *testing.B) {
            for n := 0; n < b.N; n++ {
                _ = strconv.Itoa(n) + "\t" + "test"
            }
        }))
        fmt.Println("Sprintf       ", testing.Benchmark(func(b *testing.B) {
            for n := 0; n < b.N; n++ {
                _ = fmt.Sprintf("%d\t%d", n, "test")
            }
        }))
    }
    

    При мен простата конкатенация излиза над 4 пъти по-бърза:

    concatStrConv  20000000        103 ns/op
    Sprintf         3000000        424 ns/op
    

    И тъй като също е и доста четима, няма причина да не я ползвам.

Трябва да сте влезли в системата, за да може да отговаряте на теми.