Какой язык программирования изучать на перспективу
Меня тут недавно спросили — какой язык программирования следует изучить на перспективу. Я ответил в том духе, что никаких формальных признаков того, что язык будет перспективен лет через пять, не существует и до сих пор думаю, что прав. В самом деле, если взять «моду» на языки за последние десять лет, видно, что их успех определяется подводными течениями, которые со стороны увидеть трудно, компании неисповедимы, могут «выстрелить»
Правда потом, по пути домой я задумался над этим более глубоко и теперь считаю, что популярность должны набирать языки, в которых легко, на уровне языка, делается параллелизация. Дома у меня меня ремонт сейчас
Над цифрами выше трудятся уже только оверклокеры, заливая штаны жидким азотом. Гонка частот уже, кажется, остановлена, началась гонка за количество ядер. Недавно был выпущен первый смартфон с четырьмя процессорами, а рабочая станция «Мак Про» поставляется в топовой конфигурацией с 12 процессорами. Сегодня на «Хабре» появилась новость о процессоре GA144, который будет продаваться за шестьсот рублей. У него 144 ядра.
Не говоря уже о GPU, у которых количество ядер приближается к тысячам.
Если взять
Причём «легко» не обязательно даже так, как это сделано в «Гоу» (хотя и желательно) — отдельной конструкцией языка (go), нет нужды сводить к этому всю идеологию языка, как в «Эрланге», просто чтобы это делалось, в тривиальных случаях,
Например, на «Пайтоне»
@fork
def sort(arr):
arr.sort()
return arr
# тут функция начала фоном работать
result = sort(somearray)
… много кода …
# а тут уже доступны результаты, если недоступны, то будем ждать
print([el for el in result if el])Да, это не особо эффективно, нас уже приучили разбрасываться памятью, но ещё не приучили с лёгкостью разбрасываться ядрами, ничего привыкнем, когда их станет, как грязи.
Пока, наверное, верится с трудом. Но мой первый
Многозадачность в «Гоу»
В прошлой своей записи я упомянул многозадачность в «Гоу», а сейчас вспомнил, что я ни разу не показывал как же она там выглядит с точки зрения простого программиста. Покажу на примере.
Предположим, нам нужно вычислить
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» для кодирования получившейся
Функция main — входная точка основного модуля программы, именно она (как в «Си») вызывается в самом начале.
Далее я создаю (make) небуферизированный «канал» и объявляю, что по нему будут идти строки, конструкция «:=» многим напоминает Паскаль, но отношения к нему не имеет, это синтаксический сахар для создания локальной переменной. «Канал» — это хорошее, говорящее название, хорошо отображающее суть, это действительно канал общения
В цикле создаются и сразу запускаются в фоне (конструкцией «go») на выполнение N
Внутри
Цикл не ждёт выполнения
Дальше идёт второй цикл, где N раз запускается команда на чтение из канала („… <- ch»).
Чтобы убедиться, что
У такой лёгкости использования есть свои ограничения, но об этом