Czy erlang jest naprawdę taki szybki?

Wt, 2 Czerw 2009 22:26:46 +0200

Korzystając z faktu, że mam więcej czasu niż zazwyczaj postanowiłem spędzić więcej czasu poznając Erlanga, nowoczesny język funkcyjny, słynący ze swoich malutkich procesów, braku pamięci współdzielonej między nimi oraz brakiem zmiennych w postaci znanej z innch języków programowania ;)

Po krótkich bojach czując się na siłach zachciało mi się porównania wydajności pythona oraz erlanga, w prostej operacji – nasłuchujemy na zadanym porcie, gdy klient się łączy wysyłamy mu krótki tekst po czym rozłączamy się. I tak 15 tysięcy razy, za pomocą twisteda.

Wynik?

Dodam, że nie znam się na optymalizacji erlanga, napisałem prościutki program korzystając z wbudowanych mechanizmów, żadnego grzebania w maszynie wirtualnej, żadnego Hipe, nic z tych rzeczy. Program w pythonie też bez udziwnień – korzysta jedynie z modelu forkujących się procesów.

Źródła, erlang:


-module(word_new_server).
-export([server/0]).

server() -> {ok, LSock} = gen_tcp:listen(1666, [binary, {packet, 0}, {active, false}, {reuseaddr, true}]), spawn(fun() -> con_server(LSock) end).

turn_off(Sock) -> gen_tcp:close(Sock).

con_server(LSock) -> {ok, Sock} = gen_tcp:accept(LSock), ok = gen_tcp:send(Sock, [“benchmark”]), spawn(fun() -> con_server(LSock) end), ok = turn_off(Sock).


python:
#!/usr/bin/env python
import SocketServer

class MyTcpHandler(SocketServer.BaseRequestHandler): def handle(self): self.request.send('benchmark\n’)

if name == 'main': server = SocketServer.ForkingTCPServer(('0.0.0.0’, 1666), MyTcpHandler) server.serve_forever()

Hm, no nic – muszę doczytać pewnie pozostałe rozdziały dokumentacji / źródeł, a w razie niepowodzenia zostają źródła yawsa i mochiweba :)

Komentarzy: 3

Michal Chruszcz: To wolno, a przecież forkowanie (co najmniej w Pythonie) jest relatywnie wolne. Spodziewałbym się, że erlang będzie szybszy.

xek: zrobiłem wersje, które można testować ab: erlang: -------------------------------------------------------------------------------- -module(server). -export([start/0, serve/1]). start() -> {ok, Sock} = gen_tcp:listen(1666, [binary, {packet, 0}, {active, false}, {reuseaddr, true}]), spawn(?MODULE, serve, [Sock]). serve(LSock) -> {ok, Sock} = gen_tcp:accept(LSock), spawn(fun() -> {ok, _} = gen_tcp:recv(Sock, 82), gen_tcp:send(Sock, <<"HTTP/1.0 200 OK\n\n\nTEST\n\n">>), ok = gen_tcp:close(Sock) end), serve(LSock). -------------------------------------------------------------------------------- python: -------------------------------------------------------------------------------- import SocketServer class MyTcpHandler(SocketServer.StreamRequestHandler): def handle(self): self.rfile.read(82) self.wfile.write('HTTP/1.0 200 OK\n\n\nTEST\n\n') #server = SocketServer.ForkingTCPServer(('0.0.0.0', 1666), MyTcpHandler) server = SocketServer.ThreadingTCPServer(('0.0.0.0', 1666), MyTcpHandler) server.serve_forever() -------------------------------------------------------------------------------- testy ab -c1000 -n1000 pokazują: -------------------------------------------------------------------------------- python forking: Requests per second: 332.29 [#/sec] (mean) -------------------------------------------------------------------------------- python threading: Requests per second: 1420.59 [#/sec] (mean) -------------------------------------------------------------------------------- erlang: Requests per second: 2627.19 [#/sec] (mean) CZYLI ERLANG 10x lub 2x SZYBSZY

hjs: Warto dodać, że w Erlangu takich procesów może być nawet i kilkaset tysięcy, maszyna na zwykłym domowym pccie da radę obsłużyć. Z forkami może być problem :)