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

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

Предположим, нам нужно вычислить какой-то сложный хеш (я выбрал 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»).

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

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

zg (zg.livejournal.com)
24 ноября 2011, 22:45

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

mixael (инкогнито)
25 ноября 2011, 00:25

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

Orcinus Orca (www.orcinus.ru)
25 ноября 2011, 05:04

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

Orcinus Orca (www.orcinus.ru)
25 ноября 2011, 05:53, ответ предназначен zg (zg.livejournal.com):

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

bolk (bolknote.ru)
25 ноября 2011, 06:38, ответ предназначен zg (zg.livejournal.com):

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

bolk (bolknote.ru)
25 ноября 2011, 06:39, ответ предназначен mixael

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

bolk (bolknote.ru)
25 ноября 2011, 06:44, ответ предназначен Orcinus Orca (www.orcinus.ru):

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

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

Orcinus Orca (www.orcinus.ru)
25 ноября 2011, 10:58, ответ предназначен bolk (bolknote.ru):

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

bolk (bolknote.ru)
25 ноября 2011, 12:04, ответ предназначен Orcinus Orca (www.orcinus.ru):

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

zg (zg.livejournal.com)
25 ноября 2011, 15:21, ответ предназначен Orcinus Orca (www.orcinus.ru):

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

bolk (bolknote.ru)
25 ноября 2011, 15:46, ответ предназначен zg (zg.livejournal.com):

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

zg (zg.livejournal.com)
25 ноября 2011, 16:14, ответ предназначен bolk (bolknote.ru):

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

bolk (bolknote.ru)
25 ноября 2011, 18:45, ответ предназначен zg (zg.livejournal.com):

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

funk_rabbit (funk-rabbit.livejournal.com)
25 ноября 2011, 21:02

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

bolk (bolknote.ru)
26 ноября 2011, 08:43, ответ предназначен funk_rabbit (funk-rabbit.livejournal.com):

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

Ваше имя или адрес блога (можно OpenID):

Текст вашего комментария, не HTML:

Кому бы вы хотели ответить (или кликните на его аватару)