Сейбел: Есть ли еще навыки, необходимые хорошему программисту?
Армстронг: Где-то я читал, что нужно иметь хорошую память. Думаю, это так.
Сейбел: Билл Гейтс однажды сказал, что до сих пор мог бы выйти к доске и написать большие фрагменты кода на Бейсике, который писал для Altair, хотя прошло уже лет десять. А вы можете вот так вспомнить свой старый код?
Армстронг: Да, кое-что восстановить по памяти могу. Иногда я забываю какой- нибудь старый код и совершенно не беспокоюсь - просто пишу его заново, и получается примерно то же самое. Могут измениться имена переменных, расстановка функций. Но код выйдет изоморфным. Или даже лучше, чем раньше, потому что я дополнительно его обдумал.
Возьмем, к примеру, сопоставление образцов в моем компиляторе десятилетней давности - я могу сесть и набрать его. Он будет отличаться от старой версии, но в лучшую сторону. Код как бы самоулучшается со временем. Но структура остается прежней.
Я не беспокоюсь о потере кода - если шаблоны в голове, я все вспомню. Даже не столько вспомню, сколько сделаю заново. Не думаю, что это припоминание, скорее воссоздание. Если Билл может вспомнить именно сам текст, то я - нет. Но, конечно, я долго помню структуру кода.
Сейбел: Скажите, обмен сообщениями в духе Erlang поможет раз и навсегда решить проблему параллельного программирования?
Армстронг: Нет, конечно. Это всего лишь усовершенствование, пусть и большое, по сравнению с разделяемой памятью. Думаю, Erlang выполнил, по крайней мере, одну задачу - продемонстрировал это. Работая над Erlang, мы всегда говорили на конференциях: “Надо будет копировать все данные”. И слушатели, кажется, воспринимали наши доводы насчет безотказной работы системы - копирование всех данных вводилось для этого. Нам возражали: “Но ведь тогда все будет работать страшно медленно”, - а мы отвечали: “Зато безотказно”.
Удивительно, но наш язык при определенных обстоятельствах оказывается еще и более быстрым. И то, что мы делали ради безотказной работы, во многих случаях было так же эффективно, а то и лучше, чем с разделяемой памятью. Мы спросили себя: “Почему так происходит?” Потому что улучшается распараллеливаемость. В системе с общей памятью нужно блокировать данные при обращении к ним. А блокировка обходится дорого. И потом, возможно, копировать придется не так уж много данных. Если данных немного, то копирование лучше, чем бесчисленные обновления, обращения, блокировки. А на многоядерниках, если принять старую разделяемую модель, блокировка может остановить работу всех ядер. У вас тысячеядерный процессор, одна программа делает глобальную блокировку - и тысяча ядер прекращают работу.
Я также очень сомневаюсь в неявном параллелизме. В языке могут быть параллельные конструкции, но если они не отображаются на па-рале льном процессоре, а только эмулируются системой, - преимущества никакого. Вообще, есть три вида процессорного параллелизма.
Есть конвейерный параллелизм, когда в чипе создается более длинный конвейер, чтобы делать вещи параллельно. Это предопределено при создании чипа. Обычный программист не может сделать ничего с параллелизмом на уровне инструкций.
Есть параллелизм данных; это не настоящий параллелизм, скорее он связан с процессами в кэше. Если вы хотите, чтобы программа на Си выполнялась эффективно, и если *р находится на 16-байтовой границе, то при доступе к *р доступ к *(р+1) практически бесплатен, поскольку строка кэша вытягивает его. Вам надо знать, насколько широки строки кэша, сколько байтов вы сможете утянуть при одном перемещении в кэш? Этот вид параллелизма можно успешно использовать, если быть очень осторожными со структурами данных и точно знать, где что находится в памяти. Все запутанно, и разбираться с этим не очень охота.
И наконец, многоядерные процессоры. К концу десятилетия они будут 32-ядерные, а к 2019 году ядер будут миллионы. Поэтому вам нужно взять параллельные участки своей программы и отобразить на ядра компьютера. Согласен, это довольно громоздкая операция. Вычисление начинается в другом ядре, из него потом приходит ответ - это требует времени. Если надо просто сложить два числа, это не стоит усилий - больше времени потратится на перенос данных между ядрами, чем на то, чтобы сделать все на месте.
Erlang неплохо приспособлен для этого. Программист говорит: “Мне нужен процесс, и еще, и еще”. Процессы распределяются между ядрами. Может быть, стоит подумать над их физическим распределением между ядрами. Не исключено, что процесс, порождающий другой процесс, обменивается с ним данными. Имеет смысл поместить его в то ядро, которое ближе. Если же обмен данными не очень интенсивен, то можно поместить и подальше. Процессы, занимающиеся вводом/выводом, стоило бы расположить у края чипа, с другими процессами, занимающимися вводом/выводом. Чипы становятся все больше, и надо задуматься над тем, что размещение данных в середине чипа обходится дороже, чем на краю. Если есть три сервера и база данных, то ее мы поместим в середину, а серверы, которые общаются с клиентами, на край. Но все это подлежит исследованию.
Сейбел: Вам дорога мысль о том, что Erlang - это средство, позволяющее организовать параллельные процессы. Что вам дороже - идея параллелизма на основе обмена сообщениями без разделения данных или Erlang как язык?
Армстронг: Конечно, идея. Меня спрашивают: “Что будет с Erlang? Станет ли он популярным языком?” Этого я не знаю. Думаю, он уже стал важным языком. Он может повторить судьбу Smalltalk - очень важного языка, который имел горячих сторонников, но широко не применялся. С Erlang может произойти то же самое. Возможно, заложенные в нем идеи придут к миллионам пользователей, если их реализует Microsoft в Common Language Runtime, добавив там-сям фигурных скобок.
7. Саймон Пейтон-Джонс
В 1987 году он стал одним из инициаторов проекта, в результате которого появился язык программирования Haskell. Сегодня Саймон Пейтон-Джонс - ведущий исследователь лаборатории Microsoft Research, находящейся в британском Кембридже. В 1998 году он выпустил переработанное описание языка Haskell, являющееся текущим стабильным описанием. Кроме того, Пейтон-Джонс - ведущий разработчик Glasgow Haskell Compiler (GHC), “стандартного компилятора де-факто”, согласно сайту haskell.org. Он же снабдил язык часто приводимым официальным девизом “Избегать успеха любой ценой”.
Влиятельный исследователь и бывший преподаватель, так и не получивший кандидатской степени, Пейтон-Джонс ценит как практическую, так и теоретическую красоту. Он учился программировать на машине без постоянного места хранения информации и всего со 100 ячейками памяти, а будучи студентом, писал высокоуровневые компиляторы для большого компьютера колледжа и одновременно собирал собственные простейшие машины за счет своих скудных средств. Пейтон-Джонс занялся функциональным программированием после того, как на занятии преподаватель показал способ создания цепных списков без использования мутации и раскрыл красоту “ленивых” вычислений. В функциональном программировании Пейтон Джонс увидел элегантный и дерзкий вызов всей индустрии создания программ, возможность не добавлять еще один кирпич к стене, а строить новую стену. В 2004 году был избран в члены Ассоциации вычислительной техники за “вклад в функциональные языки программирования”.
Мы говорили с ним о том, почему, по его мнению, функциональное программирование обещает изменить методы создания ПО, почему транзак-ционная память лучше приспособлена для параллельных программ, чем блокировка и переменные условия, и почему даже в Microsoft Research трудно исследовать вопрос о влиянии языка на эффективность работы программиста.
Сейбел: Когда вы научились программировать?
Пейтон-Джонс: В школе. Intel только что выпустила 4004 - первый в мире микропроцессор. Но у нас ни 4004, ни чего-нибудь похожего не было - любители в то время могли достать его лишь с большим трудом. Был только школьный компьютер IBM - странная машина, собранная из каких-