вторник, 14 декабря 2010 г.
среда, 29 сентября 2010 г.
Производительность языка Google Go
В последнее время на хабре проскальзывало несколько постов посвященных языку программирования Go, но все они по большей части носили достаточно поверхностный и ознакомительных характер. Это натолкнуло меня на мысль провести более глубокое тестировани этого языка. Для начала пару слов почему меня заинтересовал именно этот язык, а не Python, Ruby, Java и тд. Основным языком разработки последние 4 годя для меня является PHP, и поэтому я давно чуствовал потребность в изучении языка который удовлетворял бы следующим критериям:
Другой важной особенностью языка Go о которой обычно забывают упоминуть - это реализация в нем легковесных процессов(как например в Erlang или OCaml). В теории это должно резко повысить масштабируемость сетевых приложений написанных на Go, но хотелось бы узнать как дело обстоит на самом деле.
И так приступим непосредственно к тестам. На удивление написание сервера не заняло много времни:
Все что от нас потребовалось это написать функцию обработчик соединения и использовать встроенную в Go реализацию websocket сервера. Для тестирования производительности новоиспеченного демона нам понадобиться клиент, который будет создавать для него нагрузку:
Как вы можете убедиться написание websocket клиента заняло еще меньше времени. Но запускать каждый тесты вручную и замерять время нехочтся, поэтому я использовал для этих целей встроенный в язык Go механизм юнит тестировния и профилирования. Для этого достаточно создать файл echoclient_test.go и написать в нем функции вида:
Ниже исходный код функции которую я использовал для профилирования:
Теперь для того чтобы прогнать тесты нам достаточно запустить утилиту gotest и усказать ей регулярные выражения для выбора запускаемых тестов и бенчмарков. Несколько слов о том что же делает данный код - он одновременно запускает заданное количество легковесных потоков (goroutines), каждый из которых пингует наш echo сервер.
Остановлюсь немного подробнее на обработке ошибок. В Go она построена на основе 3-х встроенных функций - defer, recover и panic. Это аналог конструкции try ... catch в других языках программирования, который позволяет поймать и обработать абсолютно любую ошибку. Ключевое defer говорит компилятору о том что данную функцию необходимо выполнить непосредственно при выходе из текущей функции, причем независимо от того каким образом завершилось ее выполнение - в результате какой-либо ошибки(panic) или обычным образом. Если исполнение функции завершилось в результате ошибки то мы можем восстановить нормальное выполнение программы путем вызова функции recover.

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

А также зависимость количества успешных/провальных попыток от количества одновременных соединений:

Немного об условиях проведения тестов:
И клиент и сервер запускались на одной и тойже машине, с весьма скромными характеристиками -
Intel® Pentium® Processor T2390 (1M Cache, 1.86 GHz, 533 MHz FSB), 2GB RAM.
Выводы
Язык показал довольно высокую производительность в сетевых приложениях, но он еще недостаточно стабилен. В ходе проведения тестов обнаружилось что при нагрузке выше 1500 одновременных соединений сам сервер начал регулярно падать. Возможно дело в том что я исползовал 32 битный компилятор, в то время как основной разработчики считают именно 64 битную версию. Хочется верить что к моменту выхода протокола websockets в массы разработчики смогут довести язык Go до стабильности, достаточной для использования его в качестве основного языка для написания высоконагруженных websocket демонов.
http://smotri.com/video/view/?id=v6507567740
- Быстрота. Уточню - не на 15-25% быстрее чем в PHP/Perl/Ruby (в хорошую погоду / с попутным ветром / в цикле вычисляющем число с тремя единичками/<добавьте свое условие>), а реально быстрее - в разы, а еще лучше на порядок быстрее чем популярные интерпретируемые языки.
- Простота написания. Да писать на C/C++ это круто, это для настоящих суровых программеров(а еще лучше взять и отдельные куски кода на asm переписать, чтобы "еще быстрее" стало), но этот путь не для меня.
- Удобство написания демонов. Конечно на их Perl/PHP тоже пишут.. но я я думаю все согласяться что по надежности и стабильности работы они никогда не сравняться с аналогами написанными на C/C++.
Другой важной особенностью языка Go о которой обычно забывают упоминуть - это реализация в нем легковесных процессов(как например в Erlang или OCaml). В теории это должно резко повысить масштабируемость сетевых приложений написанных на Go, но хотелось бы узнать как дело обстоит на самом деле.
И так приступим непосредственно к тестам. На удивление написание сервера не заняло много времни:
//echod.go
package echod
import (
"http"
"io"
"websocket"
)
//Обработчик соединения
func EchoServer(ws *websocket.Conn) {
io.Copy(ws, ws)
}
func main() {
http.Handle("/echo", websocket.Handler(EchoServer))
err := http.ListenAndServe(":12345", nil)
if (err != nil) {
panic("ListenAndServe: " + err.String())
}
}
Все что от нас потребовалось это написать функцию обработчик соединения и использовать встроенную в Go реализацию websocket сервера. Для тестирования производительности новоиспеченного демона нам понадобиться клиент, который будет создавать для него нагрузку:
//echoclient.go
package echoclient;
import (
"websocket"
"log"
)
func echo() {
ws, err := websocket.Dial("ws://localhost:12345/echo", "", "http://localhost/")
defer ws.Close()
if err != nil {
panic("Dial: " + err.String())
}
pingMsg := "Hello, echod!\n"
if _, err := ws.Write([]byte(pingMsg)); err != nil {
panic("Write: " + err.String())
}
var receivedMsg = make([]byte, len(pingMsg) + 1);
if n, err := ws.Read(receivedMsg); err != nil {
panic("Read: " + err.String())
} else {
receivedMsg = receivedMsg[0:n]
}
if receivedStr := string(receivedMsg); pingMsg != receivedStr {
log.Stdoutf("Strings not equal !%s!,!%s!, %i, %i ", pingMsg, receivedStr, len(receivedStr), len(pingMsg))
}
}
func main() {
echo()
}
Как вы можете убедиться написание websocket клиента заняло еще меньше времени. Но запускать каждый тесты вручную и замерять время нехочтся, поэтому я использовал для этих целей встроенный в язык Go механизм юнит тестировния и профилирования. Для этого достаточно создать файл echoclient_test.go и написать в нем функции вида:
func TestEcho(t *testing.T) {} - для выполнения юнит тестирования и func BenchmarkEcho(b *testing.B) {} - для выполнения профилирования соответсвенно. Ниже исходный код функции которую я использовал для профилирования:
package echoclient;
import (
"testing"
)
//Функция используемая для запуска echo клиента в отдельном процессе
func echoRoutine(c chan int, index int) {
//Обработка ошибок, об этом подробнее ниже по тексту
defer func() {
//проверяем была ли какая-нибуть ошибка
if err := recover(); err != nil {
print("Routine failed:", err, "\n")
c <- -index
} else {
c <- index
print("Exit go routine\n")
}
}()
echo()
}
// Непосредственно сам бенчмарк
func BenchmarkCSP(b *testing.B) {
//b.N = 2000; - если нужно подсказываем профилировщику сколько раз мы хотим прогнать тест
// канал используемый для синхронизации потоков
c := make(chan int)
for i:= 0; i < b.N; i++ {
// запускаем каждый клиент в отдельной goroutine
go echoRoutine(c, i)
}
print("Fork all routines \n")
var (
success, failed int
)
for i:= 0; i < b.N; i++ {
//ждем когда поток вернет результат выполнения
// если он отрицательный тест провален, если положительный соответсвенно выполнен
index := <- c
if index < 0 {
failed++
print(i, ". Goroutine failed:", -index, "\n")
} else {
success++
print(i, ". Goroutine:", index, "\n")
}
}
print("Totals, success:", success," failed: ", failed, " \n")
}
Теперь для того чтобы прогнать тесты нам достаточно запустить утилиту gotest и усказать ей регулярные выражения для выбора запускаемых тестов и бенчмарков. Несколько слов о том что же делает данный код - он одновременно запускает заданное количество легковесных потоков (goroutines), каждый из которых пингует наш echo сервер.
Остановлюсь немного подробнее на обработке ошибок. В Go она построена на основе 3-х встроенных функций - defer, recover и panic. Это аналог конструкции try ... catch в других языках программирования, который позволяет поймать и обработать абсолютно любую ошибку. Ключевое defer говорит компилятору о том что данную функцию необходимо выполнить непосредственно при выходе из текущей функции, причем независимо от того каким образом завершилось ее выполнение - в результате какой-либо ошибки(panic) или обычным образом. Если исполнение функции завершилось в результате ошибки то мы можем восстановить нормальное выполнение программы путем вызова функции recover.
Результаты тестов

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

А также зависимость количества успешных/провальных попыток от количества одновременных соединений:

Немного об условиях проведения тестов:
И клиент и сервер запускались на одной и тойже машине, с весьма скромными характеристиками -
Intel® Pentium® Processor T2390 (1M Cache, 1.86 GHz, 533 MHz FSB), 2GB RAM.
Выводы
Язык показал довольно высокую производительность в сетевых приложениях, но он еще недостаточно стабилен. В ходе проведения тестов обнаружилось что при нагрузке выше 1500 одновременных соединений сам сервер начал регулярно падать. Возможно дело в том что я исползовал 32 битный компилятор, в то время как основной разработчики считают именно 64 битную версию. Хочется верить что к моменту выхода протокола websockets в массы разработчики смогут довести язык Go до стабильности, достаточной для использования его в качестве основного языка для написания высоконагруженных websocket демонов.
http://smotri.com/video/view/?id=v6507567740
пятница, 17 сентября 2010 г.
Отношение к России и русским
Это наверное то что меня больше всего удивило в финах - они очень тепло относяться к русским. То что они очень уважают и ценят русскую водку, это давно известно. Но дело этим не ограничивается. К примеру вот это я запечатлел в туалете одного фина:
И это не считая русских ушанок, касок, военных фуражек и тд. Из музыки они слушают группу ленинград (наверное сказывается близость Питера =)) и тату. Почему именно тату - вообще непонятно.. но факт что некоторым финам она знакома.
И это не считая русских ушанок, касок, военных фуражек и тд. Из музыки они слушают группу ленинград (наверное сказывается близость Питера =)) и тату. Почему именно тату - вообще непонятно.. но факт что некоторым финам она знакома.
Автомобили
Вообще что меня в финляндии удивило - большое количество очень старых(старше 10 лет) машин. И этому есть свои причины.. и главная из них драконовские налоги. Если к примеру ты решишь купить новую машину к примеру стоимостью 20 тысяч евро, то тебе придется заплатить еще около 10 тысяч евро налогов. Это просто ахтунг. Отсюда мораль - боготворите свои 13% налога... 13% это круто.
Хотя есть у них и свои прелести - кредиты очень дешевые.. всего 2-3% годовых..
Однаждый в центре Оулу я нашел заблудшее дитя советского автопрома:
Ну и в нагрузку кран:
он к советскому автопрому отношения не имеет, но он мне просто понравился.. потому что он здоровый =)
Хотя есть у них и свои прелести - кредиты очень дешевые.. всего 2-3% годовых..
Однаждый в центре Оулу я нашел заблудшее дитя советского автопрома:
он к советскому автопрому отношения не имеет, но он мне просто понравился.. потому что он здоровый =)
Мобильная связь
Сегодня пытался сменить свою pre-paid симку на post-paid, чтобы можно было по человечески интернет использовать. На pre-paid тарифе он стоит 1.5 евро за мегабит, на post-paid - 3 евро за месяц безлимитного интернета на скорости 385кб/с(это минимальная скорость). Пытался сначала получить такую симку в Saunalahtie - они сначала сказали все нормально.. дали договор.. симку.. прихожу домой пытаюсь вставить симку - херушки.. непашет.. на следующий день спрашиваю - в чем дело.. почему симка неактивирована .. они - вы знаете.. так как вы проживаете в финляндии меньше 2-х лет мы не можем вам просто так оформить контракт.. вам необходимо внести предоплату в размере 300 евро - и это при абонентской плате в 5.95 евро в месяц!!! Это все равно что заплатить за 5 лет вперед.. Хрен с вами.. пошли в dna... там картина прямо обратная.. они конечно тоже спросили сколько времени я живу в финляндии - но спокойно предоставили post-paid контракт - без требования всяких лишних бумажек.. единственное что им нужно social security number и паспорт. В салоне связи у них бесплатно предлагают кофе с молоком и мороженное.. последнее меня особенно шокировало.. просто пришел себе симку оформить.. а пока они там все это делают - перекусываешь кофем/мороженным на халяву. В общем пусть это будет маленькой рекламой dna.
Сам интернет тоже просто отличный.. и это при том что я выбрал тарифный план с миниальной скоростью.
Сам интернет тоже просто отличный.. и это при том что я выбрал тарифный план с миниальной скоростью.
пятница, 10 сентября 2010 г.
Финские рассказы
Фонтан в парке в центральном районе Хельсинки... сижу значит.. никого не трогаю.. тут мимо меня белка проскакивает... вы не подумайте - я ничего не курил... и даже не пил.. просто сдесь реально белки в центре города живут...
Подписаться на:
Сообщения (Atom)



