Ale*_*don 4 asynchronous elixir
我正在使用不同的异步HTTP服务器来查看它们如何处理多个同时连接.为了强制执行耗时的I/O操作,我使用pg_sleepPostgreSQL函数来模拟耗时的数据库查询.以下是我对Node.js所做的事情:
var http = require('http');
var pg = require('pg');
var conString = "postgres://al:al@localhost/al";
/* SQL query that takes a long time to complete */
var slowQuery = 'SELECT 42 as number, pg_sleep(0.300);';
var server = http.createServer(function(req, res) {
pg.connect(conString, function(err, client, done) {
client.query(slowQuery, [], function(err, result) {
done();
res.writeHead(200, {'content-type': 'text/plain'});
res.end("Result: " + result.rows[0].number);
});
});
})
console.log("Serve http://127.0.0.1:3001/")
server.listen(3001)
Run Code Online (Sandbox Code Playgroud)
所以这是一个非常简单的请求处理程序,它执行一个占用300毫秒的SQL查询并返回一个响应.当我尝试基准测试时,我得到以下结果:
$ ab -n 20 -c 10 http://127.0.0.1:3001/
Time taken for tests: 0.678 seconds
Complete requests: 20
Requests per second: 29.49 [#/sec] (mean)
Time per request: 339.116 [ms] (mean)
Run Code Online (Sandbox Code Playgroud)
这清楚地表明请求是并行执行的.每个请求需要300毫秒才能完成,因为我们有2批并行执行的10个请求,总共需要600毫秒.
现在我正在努力对Elixir做同样的事情,因为我听说它透明地进行异步I/O. 这是我的天真方法:
defmodule Toto do
import Plug.Conn
def init(options) do
{:ok, pid} = Postgrex.Connection.start_link(
username: "al", password: "al", database: "al")
options ++ [pid: pid]
end
def call(conn, opts) do
sql = "SELECT 42, pg_sleep(0.300);"
result = Postgrex.Connection.query!(opts[:pid], sql, [])
[{value, _}] = result.rows
conn
|> put_resp_content_type("text/plain")
|> send_resp(200, "Result: #{value}")
end
end
Run Code Online (Sandbox Code Playgroud)
如果可能相关,这是我的主管:
defmodule Toto.Supervisor do
use Application
def start(type, args) do
import Supervisor.Spec, warn: false
children = [
worker(Plug.Adapters.Cowboy, [Toto, []], function: :http),
]
opts = [strategy: :one_for_one, name: Toto.Supervisor]
Supervisor.start_link(children, opts)
end
end
Run Code Online (Sandbox Code Playgroud)
正如您所料,这不会给我预期的结果:
$ ab -n 20 -c 10 http://127.0.0.1:4000/
Time taken for tests: 6.056 seconds
Requests per second: 3.30 [#/sec] (mean)
Time per request: 3028.038 [ms] (mean)
Run Code Online (Sandbox Code Playgroud)
看起来没有并行性,请求是一个接一个地处理的.我究竟做错了什么?
更新这只是测试代码,如果你想做这样的事情,请参阅@AlexMarandon的Ecto池答案.
正如José建议的那样,我一直在玩连接设置:
defmodule Toto do
import Plug.Conn
def init(options) do
options
end
def call(conn, opts) do
{ :ok, pid } = Postgrex.Connection.start_link(username: "chris", password: "", database: "ecto_test")
sql = "SELECT 42, pg_sleep(0.300);"
result = Postgrex.Connection.query!(pid, sql, [])
[{value, _}] = result.rows
conn
|> put_resp_content_type("text/plain")
|> send_resp(200, "Result: #{value}")
end
end
Run Code Online (Sandbox Code Playgroud)
结果如下:
% ab -n 20 -c 10 http://127.0.0.1:4000/
Time taken for tests: 0.832 seconds
Requests per second: 24.05 [#/sec] (mean)
Time per request: 415.818 [ms] (mean)
Run Code Online (Sandbox Code Playgroud)