Even if an Erlang VM is now able to handle several CPUs (erlang SMP), benchmarks shows that it’s more efficient to use one VM per CPU (with SMP disabled) for tsung clients. Only the controller node is using SMP erlang. Therefore, cpu should be equal to the number of cores of your nodes. If you prefer to use erlang SMP, add the -s option when starting tsung (and don’t set cpu in the config file).
wget http://yaws.hyber.org/download/yaws-1.95.tar.gz
tar zxf yaws-1.95.tar.gz
cd yaws-1.95
# 编辑如下文件,把1250行的 `HashBin = crypto:sha(Salted),`
# 改为 `HashBin = crypto:hash(sha, Salted),` 否则会导致编译出错.
vi src/yaws_websocket.erl
./configure
make
make install
安装graphviz
生成模块依赖图需要使用到graphviz
1
apt-get install -y graphviz
编译RefactorErl
1
wget http://plc.inf.elte.hu/erlang/dl/refactorerl-0.9.14.09.tar.gz
tar zxf refactorerl-0.9.14.09.tar.gz
cd refactorerl-0.9.14.09
make
运行
进入RefactorErl Shell执行各种分析操作.
1
# -db 参数标识使用的数据库引擎
# 目前支持 Mnesia, C++ graph based 和 KyotoCabinet based graph 三种存储后端
bin/referl -db kcmini
def init([]) do
tree = [worker(Repo, [])]
supervise(tree, strategy: :one_for_all)
end
Ecto 模型
模型是用于定义在查询,验证和回调中使用的模式(Schema), 下面是一个模式定义的例子:
1
defmodule Weather do
use Ecto.Model
# weather is the DB table
schema "weather" do
field :city, :string
field :temp_lo, :integer
field :temp_hi, :integer
field :prcp, :float, default: 0.0
end
end
defmodule Repo.CreatePosts do
use Ecto.Migration
def up do
[ "CREATE TABLE IF NOT EXISTS migrations_test(id serial primary key, name text)",
"INSERT INTO migrations_test (name) VALUES ('inserted')" ]
end
def down do
"DROP TABLE migrations_test"
end
end
defp deps do
[{:postgrex, "0.5.2"},
{:ecto, "0.2.0"}
]
end
更新应用程序列表包含ecto和postgrex.
1
def application do
[applications: [:postgrex, :ecto]]
end
终端中运行mix deps.get获取依赖.
添加库(Repository)
A repo in ecto terms is the definition of a basic interface to a database, in this case PostgreSQL. Open up lib/elixir_jobs/repo.ex and add the code below. If the directory doesn’t exist, create it.
1
defmodule ElixirJobs.Repo do
use Ecto.Repo, adapter: Ecto.Adapters.Postgres
def conf do
parse_url "ecto://postgresuser:password@localhost/elixir_jobs"
end
def priv do
app_dir(:elixir_jobs, "priv/repo")
end
end
defmodule ElixirJobs do
use Application
def start(_type, _args) do
import Supervisor.Spec
tree = [worker(ElixirJobs,Repo, [])]
opts = [name: ElixirJobs.Sup, strategy: :one_for_one]
Supervisor.start_link(tree, opts)
end
end
确保一切OK, 让我们编译该项目
1
mix compile
如果没有错误消息, 然后我们需要使用psql工具添加数据库elixir_jobs.
1
$> psql -Upostgresuser -W template1
Password for user postgresuser:
template1=# CREATE DATABASE elixir_jobs;
CREATE DATABASE
template1=# \q
defmodule ElixirJobs.Jobs do
use Ecto.Model
schema "jobs" do
field :title, :string
field :type, :string
field :description, :string
field :status, :string
end
end
defmodule ElixirJobs.Repo.Migrations.CreateJob do
use Ecto.Migration
def up do
"CREATE TABLE jobs(id serial primary key, title varchar(125), type varchar(50), description text, status varchar(50))"
end
def down do
"DROP TABLE jobs"
end
end
创建了移植脚本后, 我们就可以运行它了.
移植
运行移植非常容易, 像这样:
1
$> mix ecto.migrate ElixirJobs.Repo
* running UP _build/dev/lib/elixir_jobs/priv/repo/migrations/20140802043823_create_job.exs
就这样! 如果你打开elixir_jobs数据库, 你会发现一个jobs表, 如下:
1
Column | Type | Modifiers
-------------+----------------------+---------------------------------------------------
id | integer | not null default nextval('jobs_id_seq'::regclass)
title | character varying(125) |
type | character varying(50) |
description| text |
status | character varying(50) |
$> iex -S mix
Erlang/OTP 17 [erts-6.0] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
Interactive Elixir (0.14.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> ElixirJobs.Repo.start_link
{:ok, #PID<0.108.0>}
如果返回:ok, 那么就可以使用定义模型时Ecto生成的结构插入数据了.
1
iex(2)> job = %ElixirJobs.Jobs{title: "Elixir Expert Needed", description: "ElixirDose need your help to produce a high quality Elixir article every month or two.", type: "Remote", status: "Part Time"}
iex(3)> ElixirJobs.Repo.insert(job)
%ElixirJobs.Jobs{description: "ElixirDose need your help to produce a high quality Elixir article every month or two.", id: 2, status: "Part Time", title: "Elixir Expert Needed", type: "Remote"}
打开jobs表, 就可以看到刚刚插入的数据. 现在来读取数据:
1
iex(4)> ejob = Repo.get(ElixirJobs.Jobs, 1)
%ElixirJobs.Jobs{description: "ElixirDose need your help to produce a high quality Elixir article every month or two.", id: 1, status: "Part Time", title: "Elixir Expert Needed", type: "Remote"}
iex(5)> ejob.title
"Elixir Expert Needed"
然后更新数据:
1
iex(6)> ejob = %{ejob | title: "Elixir Writer Needed"}
%ElixirJobs.Jobs{description: "ElixirDose need your help to produce a high quality Elixir article every month or two.", id: 1, status: "Part Time", title: "Elixir Writer Needed", type: "Remote"}
iex(7)> ElixirJobs.Repo.update(ejob)
:ok
验证数据已经被更新:
1
iex(8)> ElixirJobs.Repo.get(Jobs, 1)
%ElixirJobs.Jobs{description: "ElixirDose need your help to produce a high quality Elixir article every month or two.", d: 1, status: "Part Time", title: "Elixir Writer Needed", type: "Remote"}
Traceback (most recent call last):
File "/Applications/Sublime Text.app/Contents/MacOS/sublime_plugin.py", line 358, in on_query_completions
res = callback.on_query_completions(v, prefix, locations)
File "/Users/user/Library/Application Support/Sublime Text 3/Packages/ElixirSublime/elixir_sublime.py", line 270, in on_query_completions
if not session.send('COMPLETE', expand_selection(view, locations[0], aliases=aliases)):
File "/Users/user/Library/Application Support/Sublime Text 3/Packages/ElixirSublime/elixir_sublime.py", line 189, in send
self.socket.send(str.encode(cmd))
AttributeError: 'NoneType' object has no attribute 'send'
Traceback (most recent call last):
File "/Applications/Sublime Text.app/Contents/MacOS/sublime_plugin.py", line 311, in on_activated_async
callback.on_activated_async(v)
File "/Users/user/Library/Application Support/Sublime Text 3/Packages/ElixirSublime/elixir_sublime.py", line 255, in on_activated_async
self.on_load_async(view)
File "/Users/user/Library/Application Support/Sublime Text 3/Packages/ElixirSublime/elixir_sublime.py", line 260, in on_load_async
ElixirSession.ensure(os.path.dirname(filename))
File "/Users/user/Library/Application Support/Sublime Text 3/Packages/ElixirSublime/elixir_sublime.py", line 160, in ensure
session.connect()
File "/Users/user/Library/Application Support/Sublime Text 3/Packages/ElixirSublime/elixir_sublime.py", line 179, in connect
self.socket, _ = _socket.accept()
File "./socket.py", line 135, in accept
socket.timeout: timed out
10> hipe:help_option(pp_rtl).
pp_rtl - Display the intermediate HiPE-RTL code
报告编译器不同阶段的编译时间
1
12> hipe:help_option(time).
time - Reports the compilation times for the different stages
of the compiler.
{time, Module} reports timings for the module Module.
特定模块
{time, [M1, M2, M3]} reports timings for the specified modules.
指定模块列表
{time, all} reports timings all modules.
所有模块
time reports timings for the main module.
主模块
13> hipe:help_option(timeout).
timeout - Specify compilation time limit in ms. Used as {timeout, LIMIT}.
The limit must be a non-negative integer or the atom 'infinity'.
The current default limit is 15 minutes (900000 ms).
输出完成了什么
1
14> hipe:help_option(verbose).
verbose - Output information about what is being done
defmodule WsCowboy.Mixfile do
use Mix.Project
def project do
[app: :ws_cowboy,
version: "0.0.1",
elixir: "~> 1.0",
deps: deps]
end
def application do
[
applications: [:logger, :cowboy],
mod: {WsCowboy, []}
]
end
defp deps do
[{:cowboy,"~> 1.0.0"}]
end
end
We then use the extended_start_script option to tell relx that we would like to have a start script that allows us to not only start the release, but do so with the node in the background, or also to allow us to connect to a running node, and so on. This start script has the same features as the one tools like rebar generates.
Build a releasefor the current mix application.
Examples
┃ # Build a releaseusingdefaults
┃ mix release
┃
┃ # Pass args to erlexec when running the release
┃ mix release--erl="-env TZ UTC"
┃
┃ # Enable dev mode. Make changes, compile using MIX_ENV=prod
┃ # andexecute your release again to pick up the changes
┃ mix release--dev
┃
┃ # Set the verbosity level
┃ mix release--verbosity=[silent|quiet|normal|verbose]
You may pass anynumberof arguments as needed. Make sure you pass arguments
using--key=value, not --key value, as the args may be interpreted incorrectly
otherwise.
iex(7)> cond do
...(7)> "13912345678" =~ regex_cellphone == true ->
...(7)> IO.puts "Cellphone number 13912345678 is a valid cell phone number"
...(7)> true ->
...(7)> false
...(7)> end
Cellphone number 13912345678 is a valid cell phone number
:ok
在关键业务中, 还需要通过短信验证手机号的有效性, 上述验证并不能保证该号码是一个可用的手机号码.
验证电子邮件地址
1
iex(13)> str_email = "riza@elixirdose.com"
"riza@elixirdose.com"
iex(14)> Regex.match?(~r/(\w+)@([\w.]+)/, str_email)
true
iex(15)> cond do
...(15)> Regex.match?(~r/(\w+)@([\w.]+)/, str_email) == true ->
...(15)> IO.puts "Your email is a valid email"
...(15)> true ->
...(15)> IO.puts "Your email address is invalid"
...(15)> end
Your email is a valid email
:ok
defmodule RegExpTest do
def run(email_address) do
case Regex.compile("(\\w+)@([\\w.]+)") do
{:ok, regex} ->
if Regex.match?(regex, email_address) == true do
IO.puts "Your email is a valid email"
else
IO.puts "Your email address is invalid"
end
_ ->
IO.puts "Invalid regex definition"
end
end
end
在Elixir Shell中执行:
1
iex(4)> defmodule RegExpTest do
...(4)> def run(email_address) do
...(4)> case Regex.compile("(\\w+)@([\\w.]+)") do
...(4)> {:ok, regex} ->
...(4)> if Regex.match?(regex, email_address) == true do
...(4)> IO.puts "Your email is a valid email"
...(4)> else
...(4)> IO.puts "Your email address is invalid"
...(4)> end
...(4)> _ ->
...(4)> IO.puts "Invalid regex definition"
...(4)> end
...(4)> end
...(4)> end
iex:4: warning: redefining module RegExpTest
{:module, RegExpTest,
<<70, 79, 82, 49, 0, 0, 6, 160, 66, 69, 65, 77, 69, 120, 68, 99, 0, 0, 0, 122, 131, 104, 2, 100, 0, 14, 101, 108, 105, 120, 105, 114, 95, 100, 111, 99, 115, 95, 118, 49, 108, 0, 0, 0, 2, 104, 2, ...>>,
{:run, 1}}
iex(5)> RegExpTest.run("riza@elixirdose.com")
Your email is a valid email
:ok