Публикувана е втората задача за домашно. Ще ви е много полезно предварително да прочетете този гайд. Условието, както и малък тест, могат да бъдат намерени и в github хранилището ни.
Тук можете да ни питате ако има нещо неясно по условието.
Публикувана е втората задача за домашно. Ще ви е много полезно предварително да прочетете този гайд. Условието, както и малък тест, могат да бъдат намерени и в github хранилището ни.
Тук можете да ни питате ако има нещо неясно по условието.
Въпрос: в кода на условието на домашното следното:
// 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 пъти?
@Ива. Не, тъй като това е канал, щом е прочетено дадено съобщение от него, то вече не може да бъде прочетено втори път.Прочети, ако искаш малко повече за каналите :) Ето тук са добре обяснени(поне според мен).
@Ива,
Веднъж след като прочетеш нещо от канала, то вече не се намира там. Представи си, че от двете страни се подават данни. Те не се задържат вътре в самия канал (ако не е буфериран), но излезе ли нещо от него - то вече не може да бъде прочетено отново.
А каналите трябва ли да са буферирани в случая ? Постоянно ми гърми с deadlock error - и.
Hint: ако се помъчите, сигурно може и без буферирани канали да го направите, но с тях определено ще ви е по-лесно :)
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)
}
}()
}
Аз също имам подобен проблем ... Каквото и да направя хвърля deadlock. В случая ми хвърля при извикването на функцията и при начало на обхождане на даден канал във функцията ... На какво може да се дължи ?
Вероятно се опитваш да пишеш в небуфериран канал и няма кой да го прочете или се опитваш да четеш от канал, но никой не пише в него. Начертай си различните горутини (вкл. основната, която вика OrderedLogDrainer()
) и как си взаимодействат (каналите) и вероятно сам ще си отговориш на въпроса.
as a rule of thumb:
Не се опитвайте да четете и пишете в един и същ (небуфериран) канал в една горутина. Не, че няма как да се получи, но ще си спестите главоболия за момента.
Отделно, ако стартирате друга горутина да чета/пише в канал - то стартирайте я преди да сте се опитали да пишете/четете от главната.
@Антоан, програмата ти deadlock-ва като стигне реда
channel <- 1
защото никой не чете от него. Ако извикаш ламда функцията преди да пишеш в channel всичко ще е както си трябва.
П.С. Извинявам се, ноо като писах това, все още не беше излезнал отговорът на Недялко ^^
Аa, тъй като доста време никой не качи тестове, реших аз да споделя моите ^^
(edit: промених тестовете да ползват wait groups вместо да е ръчно със семафори, защото е маалко по-красиво и добавих допълнителен тестов случай)
Имам проблем с подредбата на канали(относно въпроса с поредния номер). Прерових Гугъл, изгледах и лекцията на Роб Пайк (там само спомена за това), но не мога да намеря отговор ...Как мога да кажа на даден канал " Пиши първо от first,като се затвори пиши от second" и т.н. ?
@Станислав, то отговорът на въпроса ти е направо решението на задачата ; )
Пример:
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
и не сме го затворили.
Това съвсем очаквано ще предизвика deadlock, т.е. не е валиден пример.
Задачите са проверени и примерното решение и тестовете са качени в github: https://github.com/fmi/go-homework/tree/master/tasks/02
Ако имате някакви въпроси или коментари, моля, споделете ги тук.
Защо в решението сте използвали strconv.Itoa
и конкатенация вместо просто fmt.Sprintf
?
Не, че е от особено значение в подобна задача, но 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
И тъй като също е и доста четима, няма причина да не я ползвам.
Трябва да сте влезли в системата, за да може да отговаряте на теми.