Хабрахабр

REST сервер на Прологе, как это выглядит?

В качестве небольшого экскурса для непосвященных в логическое программирование
в этом тексте будет проведен сеанс магии с разоблачением приведен подход
к созданию REST-сервера и замерены его параметры.

А все просто — будем делать на Прологе (в реализации SWI-prolog)…
Итак, что нужно. В чем подвох? Проще создать небольшой файл типа rest.pl с начальным содержимым типа
Во-первых скачать (если еще нет) и поставить собственно swi-prolog
с его сайта www.swi-prolog.org.

сервер.

и дальше загрузить его и редактировать уже средствами самой пролог-системы, вот так
(примеры приведены для консоли linux, но не сильно отличаются от windows):

$echo "сервер." > rest.pl $swipl ... ?- [rest]. true. ?- edit(сервер).

После этого запустится emacs-подобный редактор и можно все набирать в нем.

Итак, в начале все же укажем что мы будем пользоваться библиотеками и напишем что значит
запуск сервера — в прологе символы :- можно читать как «это есть»:

:- use_module(library(http/http_server)).
:- use_module(library(http/http_json)).
:- http_handler(/,сервис(M), [method(M),methods([get,post]),time_limit(10000)]). сервер :- http_server(http_dispatch, [port(8080)]).

Как видно, мы планируем что сервис будет отвечать на методы get и post.

Модельная задача

Теперь собственно, что мы будем делать. По запросу get будем отвечать страницей с полем ввода числа, при его вводе будем запрашивать метод post и вычислять это число Фиббоначии.

То есть:

сервис(get,_) :- форма(X),ответить(X).
сервис(post,Запрос) :- http_parameters(Запрос,[val(Число,[integer])]), обсчитать(Число).

Ну вот и все! Мы уже на самом деле написали наш сервер… Пролог же декларативный язык — вот мы и декларировали варианты обработки. Кстати, язык можно использовать любой — я решил местами писать на русском.

Ведь 'форма', 'ответить' и 'обсчитать' — это наши предикаты и они не определены пока. Но погодите, что же он делает? Давайте это исправим:

ответить(Вставка):- format('Content-type: text/html~n~n <html><body>Вычисление чисел Фиббоначчи<br/> ~w </body></html>~n', [Вставка]). форма('<form method="POST"><input name="val"/></form>').

Ну и приведем два варианта для обсчитать — пусть у нас числа Фиббоначчи только положительные будут:

обсчитать(Число):- Число > 0, фиббоначи(0,1,1,Число,Ответ),форма(X), format(atom(Строка),'~w число Фиббоначи равно ~w<br/>~w',[Число,Ответ,X]), ответить(Строка).
обсчитать(Число):- форма(X), format(atom(Строка),'заданное число ~w меньше 0<br/>~w',[Число,X]), ответить(Строка).

Ну и осталось определить собственно что такое число Фиббоначи:

фиббоначи(_F, F1, N, N, F1) :- !.
фиббоначи(F0, F1, I, N, F) :- F2 is F0+F1, I2 is I + 1, !,фиббоначи(F1, F2, I2, N, F).

Это определение, конечно, не по фен-шую не совсем привычное, зато считается чуть ли не быстрее чем если бы мы писали на С…

Проверяем: Итак, будет ли это работать?

?- сервер. % Started server at http://localhost:8080/ true.

Так, сервер вроде стартовал. Кстати, он многопоточный! Для проверки нужно открыть адрес
127.0.0.1:8080/ и ввести какое-нибудь число — например, 1000:

Вычисление чисел Фиббоначчи
1000 число Фиббоначи равно
4346655768693745643568852767504062580
2564660517371780402481729089536555417
9490518904038798400792551692959225930
8032263477520968962323987332247116164
2996440906533187938298969649928516003
704476137795166849228875

Ну что же, оно работает!

Небольшое исследование производительности сервера — проверим метод GET (POST очевидно сильно зависит от заданного числа, так 10000000 число считается, конечно, но несколько секунд...)

$ ab -k -c 4 -n 4000 http://127.0.0.1:8080/ ...
Concurrency Level: 4
Time taken for tests: 0.283 seconds
Complete requests: 4000
Failed requests: 0
Keep-Alive requests: 4000
Total transferred: 1108000 bytes
HTML transferred: 544000 bytes
Requests per second: 14140.57 [#/sec] (mean)
Time per request: 0.283 [ms] (mean)
Time per request: 0.071 [ms] (mean, across all concurrent requests)
Transfer rate: 3825.14 [Kbytes/sec] received
...

Что же 14140 запросов в секунду при 10 потоках — это очень неплохо для обычного компа!

Так что если вы поменяете что-то в коде, то вам достаточно в консоли набрать И да, пролог имеет такую возможность — логический вид.

?- make.

И все ваши изменения будут работать в новых запросах — ничего не нужно перегружать, останавливать и т.д.

Конечно, можно описывать rest интерфейс статически, как и сделано в примере, можно вводить всякие переменные, использовать часть пути URL как переменные — ну в общем все как обычно. Надеюсь, вам было интересно посмотреть, как создают rest-сервера на таком простом примере.

Можно подключать базы данных. Можно делать это динамически, менять логику работы программы создавая, удаляя и модифицируя предикаты — этакий самомодифицирующийся сервер, чья работа зависит от истории. В общем, все как обычно, только работать просто и приятно.

Показать больше

Похожие публикации

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»