… | |
… | |
1894 | =item * C-based event loops perform very well with small number of |
1894 | =item * C-based event loops perform very well with small number of |
1895 | watchers, as the management overhead dominates. |
1895 | watchers, as the management overhead dominates. |
1896 | |
1896 | |
1897 | =back |
1897 | =back |
1898 | |
1898 | |
|
|
1899 | =head2 THE IO::Lambda BENCHMARK |
|
|
1900 | |
|
|
1901 | Recently I was told about the benchmark in the IO::Lambda manpage, which |
|
|
1902 | could be misinterpreted to make AnyEvent look bad. In fact, the benchmark |
|
|
1903 | simply compares IO::Lambda with POE, and IO::Lambda looks better (which |
|
|
1904 | shouldn't come as a surprise to anybody). As such, the benchmark is |
|
|
1905 | fine, and shows that the AnyEvent backend from IO::Lambda isn't very |
|
|
1906 | optimal. But how would AnyEvent compare when used without the extra |
|
|
1907 | baggage? To explore this, I wrote the equivalent benchmark for AnyEvent. |
|
|
1908 | |
|
|
1909 | The benchmark itself creates an echo-server, and then, for 500 times, |
|
|
1910 | connects to the echo server, sends a line, waits for the reply, and then |
|
|
1911 | creates the next connection. This is a rather bad benchmark, as it doesn't |
|
|
1912 | test the efficiency of the framework, but it is a benchmark nevertheless. |
|
|
1913 | |
|
|
1914 | name runtime |
|
|
1915 | Lambda/select 0.330 sec |
|
|
1916 | + optimized 0.122 sec |
|
|
1917 | Lambda/AnyEvent 0.327 sec |
|
|
1918 | + optimized 0.138 sec |
|
|
1919 | Raw sockets/select 0.077 sec |
|
|
1920 | POE/select, components 0.662 sec |
|
|
1921 | POE/select, raw sockets 0.226 sec |
|
|
1922 | POE/select, optimized 0.404 sec |
|
|
1923 | |
|
|
1924 | AnyEvent/select/nb 0.085 sec |
|
|
1925 | AnyEvent/EV/nb 0.068 sec |
|
|
1926 | +state machine 0.134 sec |
|
|
1927 | |
|
|
1928 | The benchmark is also a bit unfair (my fault) - the IO::Lambda |
|
|
1929 | benchmarks actually make blocking connects and use 100% blocking I/O, |
|
|
1930 | defeating the purpose of an event-based solution. All of the newly |
|
|
1931 | written AnyEvent benchmarks use 100% non-blocking connects (using |
|
|
1932 | AnyEvent::Socket::tcp_connect and the asynchronous pure perl DNS |
|
|
1933 | resolver), so AnyEvent is at a disadvantage here as non-blocking connects |
|
|
1934 | generally require a lot more bookkeeping and event handling than blocking |
|
|
1935 | connects (which involve a single syscall only). |
|
|
1936 | |
|
|
1937 | The last AnyEvent benchmark additionally uses L<AnyEvent::Handle>, which |
|
|
1938 | offers similar expressive power as POE and IO::Lambda (using conventional |
|
|
1939 | Perl syntax), which means both the echo server and the client are 100% |
|
|
1940 | non-blocking w.r.t. I/O, further placing it at a disadvantage. |
|
|
1941 | |
|
|
1942 | As you can see, AnyEvent + EV even beats the hand-optimised "raw sockets |
|
|
1943 | benchmark", while AnyEvent + its pure perl backend easily beats |
|
|
1944 | IO::Lambda and POE. |
|
|
1945 | |
|
|
1946 | And even the 100% non-blocking version written using the high-level (and |
|
|
1947 | slow :) L<AnyEvent::Handle> abstraction beats both POE and IO::Lambda, |
|
|
1948 | even thought it does all of DNS, tcp-connect and socket I/O in a |
|
|
1949 | non-blocking way. |
|
|
1950 | |
|
|
1951 | The two AnyEvent benchmarks can be found as F<eg/ae0.pl> and F<eg/ae2.pl> |
|
|
1952 | in the AnyEvent distribution, the remaining benchmarks are part of the |
|
|
1953 | IO::lambda distribution and were used without any changes. |
|
|
1954 | |
1899 | |
1955 | |
1900 | =head1 SIGNALS |
1956 | =head1 SIGNALS |
1901 | |
1957 | |
1902 | AnyEvent currently installs handlers for these signals: |
1958 | AnyEvent currently installs handlers for these signals: |
1903 | |
1959 | |