Пишу, по большей части, про историю, свою жизнь и немного про программирование.

Многозадачность в «Гоу»

В прошлой своей записи я упомянул многозадачность в «Гоу», а сейчас вспомнил, что я ни разу не показывал как же она там выглядит с точки зрения простого программиста. Покажу на примере.

Предположим, нам нужно вычислить какой-то сложный хеш (я выбрал sha512) от трёх файлов (у меня вычисляется от одного и того же — файла программы), это может занять большое количество времени, а у нас как раз компьютер с несколькими ядрами, чего им простаивать-то? Дадим каждому ядру до заданию, пусть считают.

package main

import (
    "io"
    "os"
    "crypto/sha512"
    "encoding/hex"
    "runtime"
    "strconv"
)

func main () {
    ch := make(chan string)

    N := 3

    runtime.GOMAXPROCS(N)

    for i := 0; i<N; i++ {
        go func (name string, num int, ch chan string) {
            if f, err := os.OpenFile(name, os.O_RDONLY, 0666); err == nil {
                defer f.Close()
                h := sha512.New()

                io.Copy(h, f)

                ch <- strconv.Itoa(num) + ". " + hex.EncodeToString(h.Sum())
            } else {
                panic("Cannot open file")
            }
        }(os.Args[0], i, ch)
    }

    for ; N > 0; N-- {
        print(<-ch, "\n")
    }
}

Что здесь происходит.

Первая строка объявляет имя модуля, для основного модуля программы это имя должно быть «main», эта конструкция скажет компилятору, что именно тут находится входная точка нашей программы. На первый взгляд кажется, что в основном модуле можно было бы просто не указывать имя, но язык придерживается хорошего принципа «явное лучше неявного», чем он мне очень симпатичен.

Дальше, очевидно, подключаются модули, в языке базовых функций почти нет, поэтому даже для такой небольшой программы мне понадобилось шесть модулей: «io» для копирования данных из одного потока в другой, «os» для работы с файлом, «crypto/sha512» для хеширования, «encoding/hex» для кодирования получившейся хеш-суммы в шестнадцатеричное представление, «runtime» чтобы выставить сколько го-программ будет выполняться параллельно и «strconv» чтобы сконвертировать число в строку.

Функция main — входная точка основного модуля программы, именно она (как в «Си») вызывается в самом начале.

Далее я создаю (make) небуферизированный «канал» и объявляю, что по нему будут идти строки, конструкция «:=» многим напоминает Паскаль, но отношения к нему не имеет, это синтаксический сахар для создания локальной переменной. «Канал» — это хорошее, говорящее название, хорошо отображающее суть, это действительно канал общения го-программы с чем-то извне.

В цикле создаются и сразу запускаются в фоне (конструкцией «go») на выполнение N го-программ, которым передаётся имя файла от которого надо считать хеш, номер функции в цикле и переменная «канала» для общения.

Внутри го-программы открывается файл, он копируется во входной поток хеширующей функции, считается хеш, конвертируется в шестнадцатеричное значение и отправляется (конструкцией «ch <- smth») в «канал».

Цикл не ждёт выполнения го-программы, а просто запускает их в фоне.

Дальше идёт второй цикл, где N раз запускается команда на чтение из канала („… <- ch»).

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

У такой лёгкости использования есть свои ограничения, но об этом как-нибудь в другой раз.

15 комментариев
zg (zg.livejournal.com) 2011

компьютер с несколькими ядрами

жалко хардов с несколькими ядрами нет.

mixael 2011

Две твои крайние статьи и ссылка на хабростатью про 144-ядерный процессор, натолкнули меня странную мысль об изучении языка магистра Йоды.
Женя, а Forth ты учил?

Orcinus Orca (www.orcinus.ru) 2011

Кстати, тебе на каком языке приятней писать? Точнее какой я зык ты лучше всего понимаешь и чья идеология тебе близка?

Orcinus Orca (www.orcinus.ru) 2011

Комментарий для zg.livejournal.com:

Винты идут не с головами, а с железками. Собственно для твоих задач можно использовать RAID 0, объединяешь в него штук 40 винчестеров и получаешь не только большой объем, но и высокую скорость работы.

Евгений Степанищев (bolknote.ru) 2011

Комментарий для zg.livejournal.com:

жалко хардов с несколькими ядрами нет.

SSD

Евгений Степанищев (bolknote.ru) 2011

Комментарий для mixael:

Женя, а Forth ты учил?

Учил, но очень давно, в детстве ещё. Мне тогда он очень нравился.

Евгений Степанищев (bolknote.ru) 2011

Комментарий для www.orcinus.ru:

Кстати, тебе на каком языке приятней писать? Точнее какой я зык ты лучше всего понимаешь и чья идеология тебе близка?

Go, Python, JavaScript, Lua, PowerShell.

Когда-то ещё Sphinx С-​-​ нравился, я был ещё адептом экономии всего и вся, ещё время от времени писал на ассемблере x86. Сейчас использовать мне его просто негде, не нужна такая жёсткая экономия, а более ценно для меня моё собственное время. Разве только для развлечения и отдыха что-то на нём написать.

Orcinus Orca (www.orcinus.ru) 2011

Комментарий для Евгения Степанищева:

А какие задачи ты решаешь на PowerShell?

Евгений Степанищев (bolknote.ru) 2011

Комментарий для www.orcinus.ru:

Уже никакие (Винды нет), раньше всё подряд писал, автоматизацию всякую и прочее. Немного писал об этом в блоге: http://bolknote.ru/?powershell

zg (zg.livejournal.com) 2011

Комментарий для www.orcinus.ru:

можно использовать RAID 0

да используются. помогает оно исключительно в плане скорости. т. е. быстрее чтение запись, меньше пересечений. если каждый винт выделить для отдельного приложения — быстрее гораздо.
sas контролёр даже есть, хотя именно в плане скорости и параллельности — полное разочарование, деньги на ветер.

SSD

это тоже только скорость.

Евгений Степанищев (bolknote.ru) 2011

Комментарий для zg.livejournal.com:

это тоже только скорость.

Это не просто скорость, это скорость произвольного доступа, вот что важно. Там нет механической читающей головки и блинов, которые спозиционировать надо.

zg (zg.livejournal.com) 2011

Комментарий для Евгения Степанищева:

вы утверждаете, что ссд — это харды с несколькими ядрами. это означает как минимум для меня возможность истинно параллельного чтения/записи. где оно в ssd, я не вижу.

Евгений Степанищев (bolknote.ru) 2011

Комментарий для zg.livejournal.com:

вы утверждаете, что ссд — это харды с несколькими ядрами

Нет, я утверждаю, что в SSD проблема параллельного чтения стоит менее остро.

funk_rabbit (funk-rabbit.livejournal.com) 2011

заофтоплю: http://habrahabr.ru/blogs/webdev/130065/
интересно твое мнение :)

Евгений Степанищев (bolknote.ru) 2011

Комментарий для funk-rabbit.livejournal.com:

Я жду когда истерика уляжется. Там такие эмоции гуляют, что поддаться им — запросто.