2019/6/24

Jetty


Jetty 跟 Tomcat 一樣,都支援標準 Servlet 及 JavaEE 規範,但 Jetty 架構比 Tomcat 簡單,可以獨立運作,也可以用 embedded 的方式嵌入 project 中。目前 Jetty 支援 Servlet Spec 3.1 及 JSP 2.3,有部分規範是以模組的方式支援,可藉由設定的方式 enable/disable。


在專案配置 Jetty 只需要以 Maven POM 引用 jetty,就可以用嵌入的方式啟動 Jetty。


    <dependencies>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
            <version>9.4.12.v20180830</version>
        </dependency>
    </dependencies>

也可以直接下載 Jetty,以 standalone 方式啟動,下載 Jetty 有兩種,第一種是標準的完整的 Jetty,裡面包含了 modules 以及一個 demo server 配置。另一種是 jetty-home,是最小的 package,提供給進階使用者使用。


要啟動 Jetty 可執行下載的 $JETTY_HOME/bin 目錄中的 ./jetty.sh start,只要用 ./jetty.sh stop 停止 Jetty。


如果要以 console 模式啟動 jetty,可切換到 $JETTY_HOME 目錄,然後直接以 java 執行


java -jar start.jar

預設都是提供 http://localhost:8080 的服務,因為預設沒有部署任何 webapp,所以連接該網址後會得到 404 Error。


Jetty 裡面有個 Demo Base 配置範例,可以切換到該目錄,啟動範例


cd demo-base/
java -jar ../start.jar

可用以下指令,檢查 demo base 裡面的 modules 及 config


cd demo-base/
java -jar ../start.jar --list-modules

java -jar ../start.jar --list-config

Configuration


  • jetty.home

    定義 Jetty 主程式、lib、default modules與 default XML files 的目錄,這是不會修改異動的部分
  • jetty.base

    定義了 Jetty Server、configurtion、logs與 webapps 目錄

這兩個 properties 可透過 command line 設定,或是由環境變數 $JETTY_HOME, $JETTY_BASE 決定


以下是建立一個新的 jetty.base 目錄,然後 enable HTTP connector 與 web app deployer modules,並複製並部署 demo webapp


# JETTY_HOME 設定為下載 Jetty Distribution 解壓縮後的目錄
JETTY_HOME=~/java/jetty
JETTY_BASE=/tmp/mybase
mkdir $JETTY_BASE
cd $JETTY_BASE

直接啟動,會得到 error


$ java -jar $JETTY_HOME/start.jar
WARNING: Nothing to start, exiting ...

$ java -jar $JETTY_HOME/start.jar --create-startd
MKDIR : ${jetty.base}/start.d
INFO  : Base directory was modified

$ java -jar $JETTY_HOME/start.jar --add-to-start=http,deploy
INFO  : webapp          transitively enabled, ini template available with --add-to-start=webapp
INFO  : server          transitively enabled, ini template available with --add-to-start=server
INFO  : security        transitively enabled
INFO  : servlet         transitively enabled
INFO  : http            initialized in ${jetty.base}/start.d/http.ini
INFO  : threadpool      transitively enabled, ini template available with --add-to-start=threadpool
INFO  : deploy          initialized in ${jetty.base}/start.d/deploy.ini
MKDIR : ${jetty.base}/webapps
INFO  : Base directory was modified


$ cp $JETTY_HOME/demo-base/webapps/async-rest.war webapps/ROOT.war
$ java -jar $JETTY_HOME/start.jar

在 command line 可直接修改 http port


java -jar $JETTY_HOME/start.jar jetty.http.port=8081

但這只是暫時的設定,實際上設定值會用以下順序決定


  1. start.d/http.ini 該檔案是 http module 的設定參數
  2. modules/httpd.mod 定義料 http module 並指定使用 etc/jetty-http.xml 設定檔
  3. jetty.http.port 屬性,是由 /etc/jetty-http.xml 指定使用該屬性



後續再增加 SSL 及 http2


$ java -jar $JETTY_HOME/start.jar --add-to-start=https,http2

$ java -jar $JETTY_HOME/start.jar

啟動後,可使用 https://localhost:8443/




可用 --help 查詢所有 command line 指令


java -jar $JETTY_HOME/start.jar --help

deployment


部署 Jetty Webapp 有幾種方式,而且都可以在不停止 Jetty 的條件下,直接部署該 webapp


  1. 一個目錄 (ex: example/) 裡面有 WEB-INF 目錄,以及 web.xml,將目錄放到 $JETTY_BASE 的 webapps 目錄中,就可以部署該 webapp
  2. example.war
  3. 一個獨立的 XML 檔案,裡面定義 webapp 的相關資訊。可參考 demo-base/test.xml 為範例

在剛剛的 /tmp/mybase 新的 $JETTY_BASE 目錄中,如果要部署一個 example webapp,裡面有 JSP 網頁,必須先增加 jsp module support


$ java -jar $JETTY_HOME/start.jar --add-to-start=jsp

example 目錄結構包含一個目錄,兩個檔案


example/
    index.jsp
    WEB-INF/
        web.xml

web.xml 就是很單純的標準 webapp


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
</web-app>

啟動 jetty 後,將 example 複製到 /tmp/mybase/webapps 裡面,可看到 example hot deploy 的 log


$ java -jar $JETTY_HOME/start.jar
.....

oejsh.ContextHandler:Scanner-0: Started o.e.j.w.WebAppContext@7a5904a3{ex,/ex,file:///private/tmp/mybase/webapps/example/,AVAILABLE}{/example}

另外要注意的是,在 webapps 裡面如果有 ROOT 目錄,或是 ROOT.war,這個是 jetty server 的 default web context application。也就是 http://localhost:8080/ 連線取得的網頁。


Configuration


如何設定 jetty


POJO configuration

直些撰寫 java code 設定 jetty。或是使用 etc/jetty.xml,這是 main jetty XML config。或是利用 IoC framework (spring) 初始化 jetty objects as Spring beans

Jetty Start Configuration Files

jetty distribution 使用以下設定檔,透過 start.jar 初始化 jetty


  • ini files


    jetty 利用 command line 讀取 $JETTY_BASE/start.ini and/or $JETTY_BASE/start.d/*.ini files,產生 command line arguments


    • --module=name 啟用 module
    • name=value 用在參數化的 Jetty IoC XML
    • XML files: Jetty IoC(Spring) XML 格式
    • 標準 property file,包含附加的 start properties
    • 其他 start.jar options (java -jar start.jar --help)
    • 一些 JVM options ,以 --exec 整合,例如 -Xbootclasspath
  • mod files


    $JETTY_HOME/modules/*.mod files,以 --module=name 啟用,每個 mod 都定義了


    • module dependencies for ordering and activation
    • 需增加的 libraries
    • module 增加的 command line 參數
    • 啟用 module 需要的檔案
    • template ini,可用 --add-to-start=name 啟用
  • XML files


    Jetty IoC XML format 或是 Spring IoC format,通常放在 $JETTY_HOME/etc/ ,附加的 XML 放在 $JETTY_BASE/etc/




以下是這些設定檔的關係圖





在 Jetty 需要設定什麼?


  • Server


    核心設定檔為 /etc/jetty.xml,可加上其他 server configurations:


    • ThreadPool

      server instance 提供了一個 ThreadPool instance,這是 jetty server components 使用的預設 Executor service,可在 start.ini 或 start.d/server.ini 調整 max/min size

    • Handlers

      jetty 只能有一個 Handler instance 處理 incomping HTTP request,預設 handler tree 設定在 etc/jetty.xml,包含了 a context Handler Collection 及 Default Handler。


      Context Handler Collection 由 context path 選擇 handler,也就是 deployed Context Handler 及 Web Application Contexts


      Default Handler 無法處理的 request 會產生 404 page,可增加其他 handlers(ex: jetty-rewrite.xml, jetty-requestlog.xml) 或增加 hot deploy handlers (ex: jetty-deploy.xml)

    • Server Attributes

      server 會儲存 attribute map of strings,給 components 使用,如果 value objects 實作了 LifeCycle interface,就會 started/stopped with the server,通常 server attributes 是儲存 server-wide default values

    • Server fields

      可設定在 start.ini 或 start.d/server.init,控制 HTTP responses 的 dates, versions

    • Connectors

      接收 HTTP 或其他 protocol 的 connections

    • Services
      儲存 service objects,通常會以 LifeCycle beans 存在,例如 Login Services 及 DataSources。以 server level 設定,在 webapp 使用。

  • Connector


    network endpoint,接收某個 protocol 的 connection,標準 protocol 為 http.ini, https.ini, jetty-http2.ini


    • Port

      jetty.http.port (jetty.ssl.port),預設為 8080 (8443)
    • Host

      jetty.host 預設為 0.0.0.0

    • Idle Timeout

      在 connector 動作前,可 idle 多少 ms,否則就 close connection

    • HTTP Configuration

      包含 http, https, http2

    • SSL Context Factory

      TLS connector type (https, http2) 設定 keystore 及 truststore


    jetty 9 是以單一 ServerConnector type,他是 NIO based,並以 Connection Factories 處理多個 protocols

  • Contexts


    • contextPath

      URL prefix,例如 /foo 可處理 /foo, /foo/index.html ... 這些 URL。 / 稱為 root context

    • virtualHost

      context 可設定多個 virtual hosts,virtual host 不需要設定 network parameters。virtual host 代表 IP 的 name service alias

    • classPath

      context 可有自訂的 classpath,該 context 內執行的 handler,有增加該 classpath 的 thread context classloader。標準 webapp 會增加 WEB-INF/lib 及 WEB-INF/classes 這兩個目錄到 classpath

    • attributes

      ex: javax.servlet.context.tempdir 用在 webapp 使用 File instance 的 temp dir

    • resourceBase

      包含 static resource for the context,圖片或 html




  • Context Configuration by API


    在 embedded server,是呼叫 ContextHandler API 進行 context 設定


package org.eclipse.jetty.embedded;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;

public class OneContext
{
    public static void main( String[] args ) throws Exception
    {
        Server server = new Server( 8080 );

        // Add a single handler on context "/hello"
        ContextHandler context = new ContextHandler();
        context.setContextPath( "/hello" );
        context.setHandler( new HelloHandler() );

        // Can be accessed using http://localhost:8080/hello

        server.setHandler( context );

        // Start the server
        server.start();
        server.join();
    }
}

  • Context Configuration by IoC XML


    以下 XML 設定,提供 jetty distribution 的 javadoc context


<?xml version="1.0"  encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC
    "-//Mort Bay Consulting//DTD Configure//EN"
    "http://www.eclipse.org/jetty/configure_9_3.dtd">

<!--
  Configure a custom context for serving javadoc as static resources
-->

<Configure class="org.eclipse.jetty.server.handler.ContextHandler">
  <Set name="contextPath">/javadoc</Set>
  <Set name="resourceBase"><SystemProperty name="jetty.home" default="."/>/javadoc/</Set>
  <Set name="handler">
    <New class="org.eclipse.jetty.server.handler.ResourceHandler">
      <Set name="welcomeFiles">
        <Array type="String">
          <Item>index.html</Item>
        </Array>
      </Set>
      <Set name="cacheControl">max-age=3600,public</Set>
    </New>
  </Set>
</Configure>

  • Configuring Web Applications


    jetty 用以下方式處理 WAR application


    • classpath 包含 WEB-INF/lib, WEB-INF/classes
    • WEB-INF/web.xml 定義 init parameters, filters, servlets, listeners, security constraints, welcome files, resources
    • annotations 處理 WEB-INF/lib 是定義的 filters, servlets, listeners
    • (optional) WEB-INF/jetty-web.xml 定義 Jetty IoC config
  • Setting the Context Path


    在 WEB-INF/jetty-web.xml 可設定 context path


    <?xml version="1.0"  encoding="UTF-8"?>
    <!DOCTYPE Configure PUBLIC
    "-//Mort Bay Consulting//DTD Configure//EN"
    "http://www.eclipse.org/jetty/configure_9_3.dtd">
    
    <Configure class="org.eclipse.jetty.webapp.WebAppContext">
        <Set name="contextPath">/contextpath</Set>
    </Configure>

    也可以直接在 $JETTY_HOME/webapps/test.xml,就定義了一個 webapp,test.xml 包含 war 的位置,及 contextPath


    <?xml version="1.0"  encoding="UTF-8"?>
    <!DOCTYPE Configure PUBLIC
        "-//Mort Bay Consulting//DTD Configure//EN"
        "http://www.eclipse.org/jetty/configure_9_3.dtd">
    
    <Configure class="org.eclipse.jetty.webapp.WebAppContext">
      <Set name="war"><SystemProperty name="jetty.home" default="."/>/webapps/test.war</Set>
      <Set name="contextPath">/test</Set>
    </Configure>
  • Setting an Authentication Realm


    標準 realm name 設定在 web.xml,例如以下是宣告使用 BASIC authentication,並使用 "Test Realm"


    <login-config>
      <auth-method>BASIC</auth-method>
      <realm-name>Test Realm</realm-name>
    </login-config>

    "Test Realm" 設定在 $JETTY_BASE/etc/test-realm.xml,並傳入 start.ini 及 start.d/server.ini


    以下設定 LoginService


    <?xml version="1.0"?>
    <!DOCTYPE Configure PUBLIC "-" "http://www.eclipse.org/jetty/configure_9_3.dtd">
    <Configure id="Server" class="org.eclipse.jetty.server.Server">
        <!-- =========================================================== -->
        <!-- Configure Authentication Login Service                      -->
        <!-- Realms may be configured for the entire server here, or     -->
        <!-- they can be configured for a specific web app in a context  -->
        <!-- configuration (see $(jetty.home)/webapps/test.xml for an    -->
        <!-- example).                                                   -->
        <!-- =========================================================== -->
        <Call name="addBean">
          <Arg>
            <New class="org.eclipse.jetty.security.HashLoginService">
              <Set name="name">Test Realm</Set>
              <Set name="config"><Property name="jetty.demo.realm" default="etc/realm.properties"/></Set>
              <Set name="hotReload">false</Set>
            </New>
          </Arg>
        </Call>
    
        <Get class="org.eclipse.jetty.util.log.Log" name="rootLogger">
          <Call name="warn"><Arg>demo test-realm is deployed. DO NOT USE IN PRODUCTION!</Arg></Call>
        </Get>
    </Configure>

隱藏 Server 資訊


在 start.ini 將 server module 裡面的 jetty.httpConfig.sendServerVersion 設定改為 false


--module=server
## Whether to send the Server: header
jetty.httpConfig.sendServerVersion=false

References


The Definitive Reference


CentOS 7 安装jetty


Deploying Web Applications in Jetty


system service


Setup SSL in Jetty

2019/6/16

julia Data Visulization


分成三個部分: Basic Plots, Vega, Gadfly,討論如何在 julia 進行 data visulization


Basic plots


使用 PyPlot,這是以 python matplotlib.pyplot module 提供的功能


使用前要先安裝 matplotlib


python -m pip install matplotlib

在 julia 安裝 PyPlot


 Pkg.add("PyPlot")

用以下指令在 julia 測試 PyPlot


using PyPlot
x = 1:100
y = rand(100)
p = PyPlot.plot(x,y)
xlabel("x")
ylabel("y")
title("basic plot")
grid("true")

會得到這樣的圖形結果



另一個例子


using PyPlot

x = range(0, stop=4pi, length=1000)
y = cos.(pi .+ sin.(x))

xlabel("x-axis")
ylabel("y-axis")
title("using sin and cos functions")

plot(x, y, color="red")


XKCD 是一種 casual-style, handwritten graph mode


using PyPlot

x = [1:1:10;]
y = ones(10)

for i = 1:1:10
    y[i] = pi + i*i
end

xkcd()
xlabel("x-axis")
ylabel("y-axis")
title("XKCD")
plot(x,y)


bar chart


using PyPlot

x = [10,20,30,40,50]
y = [2,4,6,8,10]
xlabel("x-axis")
ylabel("y-axis")
title("Vertical bar graph")
bar(x, y, color="red")


horizontal bar chart


clf()
x = [10,20,30,40,50]
y = [2,4,6,8,10]
title("Horizontal bar graph")
xlabel("x-axis")
ylabel("y-axis")
barh(x,y,color="red")

2D histogram


clf()
x = rand(1000)
y = rand(1000)
xlabel("x-axis")
ylabel("y-axis")
title("2D Histograph")
hist2D(x, y, bins=50)

pie chart


clf()
labels = ["Fruits";"Vegetables";"Wheat"]
colors = ["Orange";"Blue";"Red"]
sizes = [25;40;35]
explode = zeros(length(sizes))
fig = figure("piechart", figsize=(10,10))
p = pie(sizes, labels=labels, shadow=true, startangle=90, colors = colors)
title("Pie charts")


Scatter chart


clf()
fig = figure("scatterplot", figsize = (10,10))
x = rand(50)
y = rand(50)
areas = 1000*rand(50);
scatter(x, y, s=areas, alpha=0.5)
xlabel("x-axis")
ylabel("y-axis")
title("Scatter Plot")



PyPlot 的 3D plot 是使用 surf(x, y, z, facecolors=colors)


參數 說明
X,Y,Z Data values as 2D arrays
rstride Array row stride (step size)
cstride Array column stride (step size)
rcount Use at most this many rows, defaults to 50
ccount Use at most this many columns, defaults to 50
color Color of the surface patches
cmap A colormap for the surface patches.
facecolors Face colors for the individual patches
norm An instance of Normalize to map values to colors
vmin Minimum value to map
vmax Maximum value to map
shade Whether to shade the facecolors

using PyPlot

clf()
a = range(0.0, stop=2pi, length=500)
b = range(0.0, stop=2pi, length=500)

len_a = length(a)
len_b = length(b)

x = ones(len_a, len_b)
y = ones(len_a, len_b)
z = ones(len_a, len_b)

for i=1:len_a
    for j=1:len_b
        x[i,j] = sin(a[i])
        y[i,j] = cos(a[i])
        z[i,j] = sin(b[j])
    end
end

colors = rand(len_a, len_b, 3)
fig = figure()
surf(x, y, z, facecolors=colors)
fig[:canvas][:draw]()


Gadfly


這是一個圖形的 library,可以輸出圖片為 SVG, PNG, PostScript, PDF,也可用 IJulia 運作,跟 DataFrames 緊密整合,提供 pan, zoom, toggle 的功能。執行 Gadfly.plot 後,browser 會打開一個 html 檔案,裡面是 svg 圖片。


Pkg.add("Gadfly")
using Gadfly
Gadfly.plot(x = rand(10), y=rand(10))


# 折線圖
Gadfly.plot(x = rand(10),y=rand(10), Geom.point, Geom.line)

Gadfly.plot(x=1:10, y=[10^n for n in rand(10)], Scale.y_sqrt, Geom.point, Geom.smooth, Guide.xlabel("x"), Guide.ylabel("y"), Guide.title("Graph with labels"))




Plotting DataFrames with Gadfly

使用 RDatasets (有一些範例資料) 產生 DataFrame for the plot function


折線圖


using RDatasets
Gadfly.plot(dataset("datasets", "iris"),
        x="SepalLength",
        y="SepalWidth",
        Geom.line)


Point Plot


Gadfly.plot(dataset("datasets", "iris"),
        x="SepalLength",
        y="SepalWidth",
        Geom.point)


plot a graph between SepalLength and SepalWidth



histogram


Gadfly.plot(x=randn(4000), Geom.histogram(bincount=100))


preceding showcased histogram


Gadfly.plot(dataset("mlmRev", "Gcsemv"),
        x = "Course", color="Gender", Geom.histogram)


References


Learning Julia

2019/6/10

Numerical and Scientific Computation in Julia

julia 提供處理大量資料,以及進行統計運算的 library


Working with data


首先是讀取資料的方式,如果是 binary 資料,可直接用 read(), write()


julia> for val in [:Bool, :Char, :Int8]
         @eval println(@which read(stdin, $val))
       end
read(s::IO, ::Type{Bool}) in Base at io.jl:593
read(io::IO, ::Type{Char}) in Base at io.jl:613
read(s::IO, ::Type{Int8}) in Base at io.jl:588

使用


julia> read(stdin, Char)
j
'j': ASCII/Unicode U+006a (category Ll: Letter, lowercase)

julia> read(stdin, Bool)
true
true

julia> read(stdin, Int8)
12
49

readline


julia> methods(readline)
# 4 methods for generic function "readline":
[1] readline(s::IOStream; keep) in Base at iostream.jl:433
[2] readline() in Base at io.jl:370
[3] readline(filename::AbstractString; keep) in Base at io.jl:364
[4] readline(s::IO; keep) in Base at io.jl:370

使用


julia> number = parse(Int64, readline())
12
12

julia> println(number)
12



working with text files

open 參數除了 filename,後面還有存取該檔案的 mode


julia> methods(open)
# 8 methods for generic function "open":
[1] open(fname::AbstractString; read, write, create, truncate, append) in Base at iostream.jl:275
[2] open(fname::AbstractString, mode::AbstractString) in Base at iostream.jl:339
[3] open(f::Function, cmds::Base.AbstractCmd, args...) in Base at process.jl:615
[4] open(f::Function, args...; kwargs...) in Base at iostream.jl:367
[5] open(cmds::Base.AbstractCmd) in Base at process.jl:584
[6] open(cmds::Base.AbstractCmd, mode::AbstractString) in Base at process.jl:562
[7] open(cmds::Base.AbstractCmd, mode::AbstractString, other::Union{RawFD, FileRedirect, IO}) in Base at process.jl:562
[8] open(cmds::Base.AbstractCmd, other::Union{RawFD, FileRedirect, IO}; write, read) in Base at process.jl:584

Mode Description
r read
r+ read, write
w write, create, truncate
w+ read, write, create, truncate
a write, create, append
a+ read, write, create, append

# 有個文字檔 sample.txt
shell> cat sample.txt

file = open("sample.txt")

# 以行為單位,讀入文字檔
file_data = readlines(file)

enumerate(file_data)

# 加上行號
for lines in enumerate(file_data)
   println(lines[1],"-> ", lines[2])
end

# 大寫列印
for line in file_data
   println(uppercase(line))
end

# 反過來列印
for line in file_data
   println(reverse(line))
end

# 計算行數
countlines("sample.txt")

# 列印第一行
first(file_data)

# 最後一行
last(file_data)

working with CSV

using DelimitedFiles

csvfile = readdlm("sample.csv", ',', String, '\n')

# 只取得第二欄資料
csvfile[:,2]

# 只取前三行資料
csvfile[1:3,:]

# 以 | 區隔資料的 sample.psv
# "Lora"|"UK"
# "James"|"UK"
readdlm("sample.psv",'|')

working with DataFrames

DataFrame 是一種類似 database 的資料結構,可以用類似 SQL 的方式存取 DataFrames


using DataFrames

# 取得所有 DataFrames 支援的 functions
names(DataFrames)

DataFrame: 2D data structure,類似 R 與 Pandas 的 DataFrame


  • DataArray: 比 julia 預設 Array type 提供更多 comparison 的功能,但目前已經 deprecated (ref: https://github.com/JuliaStats/DataArrays.jl)
  • DataFrame: 2D data structure,類似 R 與 Pandas 的 DataFrame



julia 的 Array 以 nothing 代表 missing value


julia> a = [1,2,3,nothing,5,6]
6-element Array{Union{Nothing, Int64},1}:
 1
 2
 3
  nothing
 5
 6

julia> typeof(a[4])
Nothing



DataFrame: https://juliadata.github.io/DataFrames.jl/stable/man/getting_started.html


julia> dframe = DataFrame(Names = ["John","May"], Age = [27,28])
2×2 DataFrame
│ Row │ Names  │ Age   │
│     │ String │ Int64 │
├─────┼────────┼───────┤
│ 1   │ John   │ 27    │
│ 2   │ May    │ 28    │

julia> dframe.Names
2-element Array{String,1}:
 "John"
 "May"

julia> dframe.Age
2-element Array{Int64,1}:
 27
 28

julia> names(dframe)
2-element Array{Symbol,1}:
 :Names
 :Age

julia> describe(dframe)
2×8 DataFrame
│ Row │ variable │ mean   │ min  │ median │ max │ nunique │ nmissing │ eltype   │
│     │ Symbol   │ Union… │ Any  │ Union… │ Any │ Union…  │ Nothing  │ DataType │
├─────┼──────────┼────────┼──────┼────────┼─────┼─────────┼──────────┼──────────┤
│ 1   │ Names    │        │ John │        │ May │ 2       │          │ String   │
│ 2   │ Age      │ 27.5   │ 27   │ 27.5   │ 28  │         │          │ Int64    │



另外有個獨立的 CSV 套件,可處理 csv file,讀入 CSV file 後,就得到 DataFrame 物件


using Pkg
Pkg.add("CSV")
using CSV

julia> CSV.read("sample.csv")
3×2 DataFrame
│ Row │ Lora    │ UK      │
│     │ String⍰ │ String⍰ │
├─────┼─────────┼─────────┤
│ 1   │ James   │ UK      │
│ 2   │ Raj     │ India   │
│ 3   │ May     │ America │

Linear algebra


產生 matrix


# 亂數 3x3 matrix
julia> A = rand(3,3)
3×3 Array{Float64,2}:
 0.108282  0.433033  0.247145
 0.571936  0.369386  0.547845
 0.423382  0.380503  0.77661

# array 且初始為 1
julia> ones(5)
5-element Array{Float64,1}:
 1.0
 1.0
 1.0
 1.0
 1.0



Vector 與 Matrix 的差異


Vector{T} 是 Array{T, 1} 的 alias,Matrix{T} 是Array{T, 2} 的 alias


julia> Vector{Float64} == Array{Float64,1}
true

julia> Matrix{Float64} == Array{Float64,2}
true



矩陣乘法


julia> A = rand(3,3)
3×3 Array{Float64,2}:
 0.167005  0.188954  0.0483164
 0.82603   0.440255  0.00107621
 0.137211  0.308508  0.724953

julia> b = 2*A
3×3 Array{Float64,2}:
 0.334011  0.377909  0.0966328
 1.65206   0.88051   0.00215241
 0.274422  0.617015  1.44991

julia> b= 2A
3×3 Array{Float64,2}:
 0.334011  0.377909  0.0966328
 1.65206   0.88051   0.00215241
 0.274422  0.617015  1.44991



transpose 轉置矩陣


julia> transpose_of_A = A'
3×3 LinearAlgebra.Adjoint{Float64,Array{Float64,2}}:
 0.167005   0.82603     0.137211
 0.188954   0.440255    0.308508
 0.0483164  0.00107621  0.724953



inverse 逆矩陣


julia> inv(A)
3×3 Array{Float64,2}:
 -6.31559   2.41816    0.417329
 11.8591   -2.26692   -0.787013
 -3.85134   0.507016   1.63533



Determinant 行列式


julia> using LinearAlgebra

julia> det(A)
-0.05048337143385562



Eigenvalues 特徵向量


julia> eigvals(A)
3-element Array{Float64,1}:
 -0.1016764648907107
  0.5846559789763167
  0.8492342814186749



方程式運算


julia> 5
5

julia> equation = 3x^2 + 4x + 3
98

Differential calculus


Pkg.add("Calculus")
using Calculus
names(Calculus)

julia> f(x) = sin(x)
f (generic function with 1 method)
        
julia> f'(1.0)
0.5403023058631036

julia> f'(1.0) - cos(1.0)
-5.036193684304635e-12

julia> f''(1.0) - (-sin(1.0))
-6.647716624952338e-7

julia> differentiate("cos(x) + sin(x) + exp(-x) * cos(x)", :x)
:(1 * -(sin(x)) + 1 * cos(x) + ((-1 * exp(-x)) * cos(x) + exp(-x) * (1 * -(sin(x)))))

julia> differentiate("sin(x)", :x)
:(1 * cos(x))

julia> differentiate("cos(x) + sin(y) + exp(-x) * cos(y)", [:x, :y])
2-element Array{Any,1}:
 :(1 * -(sin(x)) + ((-1 * exp(-x)) * cos(y) + exp(-x) * 0))
 :(1 * cos(y) + (0 * cos(y) + exp(-x) * (1 * -(sin(y)))))

Statistics


JuliaStats 所列出支援的 packages


  • DataFrames
  • Distributions: probability distribution
  • MultivariateStats: Multivariate statistical analysis
  • HypothesisTests
  • MLBase: Swiss knife for machine learning
  • Distances: Various distances between vectors
  • KernelDensity
  • Clustering: algorithm for data clustering
  • GLM: Generalized linear models
  • NMF: Nonnegative matrix factorization
  • RegERMs: Regularized empirical risk minimization
  • MCMC: Markov Chain Monte Carlo
  • TimeSeries: time series analysis



simple statistics

julia> using Statistics

julia> x = [10,20,30,40,50]

julia> mean(x)
30.0

# 中位數 median
julia> median(x)
30.0

julia> sum(x)
150

# 標準差
julia> std(x)
15.811388300841896

# variance 變異數
julia> var(x)
250.0

julia 也支援 cumulative operations 的 functions


  • accumulate
  • cumsum(): cumulative summation
  • cumprod(): cumulative product

julia> accumulate(+, x)
5-element Array{Int64,1}:
  10
  30
  60
 100
 150

julia> accumulate(-, x)
5-element Array{Int64,1}:
   10
  -10
  -40
  -80
 -130

julia> cumsum(x)
5-element Array{Int64,1}:
  10
  30
  60
 100
 150

julia> cumprod(x)
5-element Array{Int64,1}:
       10
      200
     6000
   240000
 12000000

julia> for i in [:cumsum,:cumprod]
               @eval print($i, "->")
               @eval println($i(x))
       end
cumsum->[10, 30, 60, 100, 150]
cumprod->[10, 200, 6000, 240000, 12000000]



statistics using DataFrames

julia> using DataFrames

julia> dframe = DataFrame(Subjects = ["Maths","Physics","Chemistry"],Marks = [90,85,95])
3×2 DataFrame
│ Row │ Subjects  │ Marks │
│     │ String    │ Int64 │
├─────┼───────────┼───────┤
│ 1   │ Maths     │ 90    │
│ 2   │ Physics   │ 85    │
│ 3   │ Chemistry │ 95    │

julia> describe(dframe)
2×8 DataFrame
│ Row │ variable │ mean   │ min       │ median │ max     │ nunique │ nmissing │ eltype   │
│     │ Symbol   │ Union… │ Any       │ Union… │ Any     │ Union…  │ Nothing  │ DataType │
├─────┼──────────┼────────┼───────────┼────────┼─────────┼─────────┼──────────┼──────────┤
│ 1   │ Subjects │        │ Chemistry │        │ Physics │ 3       │          │ String   │
│ 2   │ Marks    │ 90.0   │ 85        │ 90.0   │ 95      │         │          │ Int64    │



Pandas

對習慣使用 python 進行資料分析的使用者來說,Pandas 是比較常用的 package


julia> pandasDataframe = Pandas.DataFrame(Dict(:Subjects => ["Maths","Physics","Chemistry"],:Marks => [90,85,95]))
   Marks   Subjects
0     90      Maths
1     85    Physics
2     95  Chemistry


julia> Pandas.describe(pandasDataframe)
       Marks
count    3.0
mean    90.0
std      5.0
min     85.0
25%     87.5
50%     90.0
75%     92.5
max     95.0


julia> pandasDataframe[:Subjects]
0        Maths
1      Physics
2    Chemistry
Name: Subjects, dtype: object


julia> pandasDataframe[:Marks]
0    90
1    85
2    95
Name: Marks, dtype: int64


julia> query(pandasDataframe,:(Marks>90))
   Marks   Subjects
2     95  Chemistry



Distributions

distributions.jl 有以下功能


  • Moments (ex: mean, variance, skewness, and kurtosis), entropy, and other properties
  • Probability density/mass functions (pdf) and their logarithms (logpdf)
  • Moment generating functions and characteristic functions
  • Maximum likelihood estimation
  • Posterior w.r.t. conjugate prior and Maximum-A-Posteriori (MAP) estimation

using Pkg
Pkg.add("Distributions")
using Distributions

distribution = Normal()

# 以 normal distribution 產生 10 筆 random 資料
x = rand(distribution, 10)

Binomial()

Cauchy()

Poisson()



TimeSeries

Pkg.add("TimeSeries")
Pkg.add("MarketData")

using TimeSeries

julia> dates  = collect(Date(2017,8,1):Day(1):Date(2017,8,5))
5-element Array{Date,1}:
 2017-08-01
 2017-08-02
 2017-08-03
 2017-08-04
 2017-08-05

julia> sample_time = TimeArray(dates, rand(length(dates)))
5×1 TimeArray{Float64,1,Date,Array{Float64,1}} 2017-08-01 to 2017-08-05
│            │ A      │
├────────────┼────────┤
│ 2017-08-01 │ 0.9142 │
│ 2017-08-02 │ 0.0834 │
│ 2017-08-03 │ 0.417  │
│ 2017-08-04 │ 0.4778 │
│ 2017-08-05 │ 0.6859 │



Hypothesis testing

測試 sample data 是否有足夠的 evidence,針對整個 population of data 進行條件測試。


有兩種 hypothesis testing 測試方式


  • Null hypothesis: the statement being tested
  • Alternative hypothesis: the statement that you will be able to conclude as true

Pkg.add("HypothesisTests")
using HypothesisTests

using Distributions

julia> sampleOne = rand(Normal(), 10)
10-element Array{Float64,1}:
 -0.5347603532683008
 -0.7882658160278007
 -0.3314222340035204
 -0.9280782524368908
  0.4540819395751322
  1.056554282551302
  1.2211198338710754
 -0.7067184060685551
  0.9788402691232629
  0.39421862072760827

julia> testOne = OneSampleTTest(sampleOne)
One sample t-test
-----------------
Population details:
    parameter of interest:   Mean
    value under h_0:         0
    point estimate:          0.0815569884043313
    95% confidence interval: (-0.514, 0.6771)

Test summary:
    outcome with 95% confidence: fail to reject h_0
    two-sided p-value:           0.7638

Details:
    number of observations:   10
    t-statistic:              0.3097695342286937
    degrees of freedom:       9
    empirical standard error: 0.2632827937950805


julia> @which OneSampleTTest(sampleOne)
OneSampleTTest(v::AbstractArray{T,1}) where T<:Real in HypothesisTests at /Users/charley/.julia/packages/HypothesisTests/M3Ysg/src/t.jl:98

julia> pvalue(testOne)
0.7637885831202397

julia> pvalue(testOne, tail=:right)
0.38189429156011984

julia> pvalue(testOne, tail=:left)
0.6181057084398802

# check whether 25 successes from 1000 samples is inconsistent with a 50% success rate
julia> BinomialTest(25, 1000, 0.50)
Binomial test
-------------
Population details:
    parameter of interest:   Probability of success
    value under h_0:         0.5
    point estimate:          0.025
    95% confidence interval: (0.0162, 0.0367)

Test summary:
    outcome with 95% confidence: reject h_0
    two-sided p-value:           <1e-99

Details:
    number of observations: 1000
    number of successes:    25

Optimization


optimization 是 finding best solution from all feasible solutions 的問題,可分為兩類


  • continuous optimization problem
  • combinatorial optimization problem (discrete)

某些問題可以用 optimization 方法解決


  • Shortest path
  • Maximum flow through a network
  • Vehicle routing

juila 將 optimization packages 集合在 JuliaOpt,其中有兩個最重要的 packages,這兩個都是 AML(Algebraic modeling languages),放在 MathProgBase.jl 裡面


  • JuMP (Julia for Mathematical Programming)
  • Convex.jl



JuMP

Python 習慣使用 PuLP


Pkg.add("JuMP")
Pkg.add("Clp")
using JuMP
using Clp

julia> m = JuMP.Model()
Feasibility problem with:
 * 0 linear constraints
 * 0 variables
Solver is default solver

julia> m = JuMP.Model(solver = Clp.ClpSolver())
Feasibility problem with:
 * 0 linear constraints
 * 0 variables
Solver is Clp



optimiser.jl


using JuMP
using Clp

m = Model(solver = ClpSolver())
@variable(m, 0 <= a <= 2 )
@variable(m, 0 <= b <= 10 )

@objective(m, Max, 5a + 3*b )
@constraint(m, 1a + 5b <= 3.0 )

print(m)

status = solve(m)

println("Objective value: ", getobjectivevalue(m))
println("a = ", getvalue(a))
println("b = ", getvalue(b))

執行


$ julia optimiser.jl
Max 5 a + 3 b
Subject to
 a + 5 b ≤ 3
 0 ≤ a ≤ 2
 0 ≤ b ≤ 10
Objective value: 10.6
a = 2.0
b = 0.2

Convex.jl

用在 disciplined convex programming,使用 Convex 需要 solver,也就是 SCS


Pkg.add("Convex")
Pkg.add("SCS")

using Convex
using SCS

X = Variable(2, 2)

y = Variable()

p = minimize(vecnorm(X) + y, 2 * X <= 1, X' + y >= 1, X >= 0, y >= 0)

solve!(p)

println(X.value)

println(y.value)

p.optval

References


Learning Julia

2019/6/3

Interoperability and Meta Programming


julia 可跟 C, Python 的程式互動。另外 juila 支援 meta programming 的形式。


Interacting with OS


在 REPL 可用 ; 進入 shell,執行 shell commands,如果在 julia,則是直接用 pwd()


shell> pwd
/Users/user

julia> pwd()
"/Users/user"



filesystem operations

存取檔案的 functions


  • homedir(), joinpath()


    為支援 linux, windows,使用 joinpath() 產生檔案的路徑


julia> homedir()
"/Users/user"

julia> joinpath(homedir(), "Documents")
"/Users/user/Documents"

  • pwd(), cd()


    取得目前的目錄,以及切換目錄


    cd("../")
  • readdir()


    取得目錄內的檔案列表,包含目錄及檔案


    readdir(".")
  • mkdir()


    d = joinpath(homedir(), "LearningJulia")
    mkdir(d)
  • stat


    stat("somefile") 會取得 StatStruct(mode=0o100644, size=28676),而 StatStruct 裡面有這些欄位


    ref: https://github.com/JuliaLang/julia/blob/master/base/stat.jl


    ex: stat("somefile").size


    Name Description
    size The size (in bytes) of the file
    device ID of the device that contains the file
    inode The inode number of the file
    mode The protection mode of the file
    nlink The number of hard links to the file
    uid The user id of the owner of the file
    gid The group id of the file owner
    rdev If this file refers to a device, the ID of the device it refers to
    blksize The file-system preferred block size for the file
    blocks The number of such blocks allocated
    mtime Unix timestamp of when the file was last modified
    ctime Unix timestamp of when the file was created

    • cp, mv

    julia> cp("test", "test1")
    "test1"
    
    julia> isfile("test1")
    true
    
    julia> mv("test1", "test2")
    "test2"

  • isdir, homedir, basename, dirname, and splitdir


    julia> homedir()
    "/Users/user"
    
    julia> joinpath(homedir(), "Documents")
    "/Users/user/Documents"
    
    julia> isdir(joinpath(homedir(), "Documents"))
    true
    
    julia> basename(homedir())
    "user"
    
    julia> dirname(homedir())
    "/Users"
    
    julia> splitdir(homedir())
    ("/Users", "user")
    
  • mkpath, ispath, abspath, and joinpath


    julia> ispath(homedir())
    true
    
    julia> abspath(".")
    "/Users/user/Downloads/"
    
    julia> joinpath(homedir(), "Documents")
    "/Users/user/Documents"
    
    julia> mkpath(joinpath("Users","adm"))
    "Users/adm"
    
    julia> for (root, dirs, files) in walkdir("Users")
                   println("Directories in $root")
           end
    Directories in Users
    Directories in Users/adm



I/O Operations

STDOUT, STDERR, STDIN 是三個 global variables,分別為 standard output, error, input stram


open(), close(), write, read


julia> file = open("sample.txt")
IOStream(<file sample.txt>)

julia> file
IOStream(<file sample.txt>)

julia> lines = readlines(file)
2-element Array{String,1}:
 "Hi there!"
 "Learning Julia is so much fun."

julia> write("sample.txt", "hi how are you doing?")
21

julia> read("sample.txt")
21-element Array{UInt8,1}:

julia> readline("sample.txt")
"hi how are you doing?"

julia> close(file)



讀取某個文字檔,計算裡面有幾個 "Julia" 這個 word


# Arguments
# ARGS[0] is the command itself
in_file = ARGS[1]
out_file = ARGS[2]

# Keeping track using a counter
counter = 0
for line in eachline(in_file)
    for word in split(line)
        if word == "Julia"
            global counter += 1
        end
    end
end

# Write the contents to the o/p file
write(out_file, "The count for the word julia is $counter")

# Finally, read the contents to inform the user
for line in readlines(out_file)
    println(line)
end

shell> julia sample.jl sample.txt out.txt
The count for the word julia is 4

Calling C and Python


Calling C from Julia

compile (ex: LLVM) 需要知道什麼,才能由 Julia 呼叫 C


  • Name of the library
  • Name of the function
  • Number and types of the arguments (也稱為 Arity)
  • return type of the function
  • values of the arguments passed

julia 使用 ccall((:name,"lib"), return_type, (arg1_type, arg2_type...), arg1, arg2) 處理


呼叫 C 標準函式庫的 clock function


julia> ccall((:clock, :libc), Int64, ())
3206897

julia> ccall((:clock, :libc), Cint, ())
3213482

julia> Int32 == Cint
true

Cint 是 C 的資料型別,等於 signed int c-type,另外還有 Cint, Cuint, Clong, Culong, and Cchar




呼叫 getenv,取得 SHELL value,Ptr{Cchar} 是參數的資料型別,後面 return value 資料型別也是 Ptr{Cchar}


julia> syspath = ccall( (:getenv, :libc), Ptr{Cchar}, (Ptr{Cchar},), "SHELL")
Ptr{Int8} @0x00007ffee37b857a

julia> unsafe_string(syspath)
"/bin/bash"

C 的 struct 可以替換為 julia 的 composite types


Calling Python form Julia

使用 PyCall


julia> using Pkg

julia> Pkg.add("PyCall")

julia> using PyCall

julia> py"len('julia')"
5

julia> py"str(5)"
"5"

julia> py"""
       print('hello world')
       """
hello world



如果要使用 python 的 built-in data type (ex: dict),可使用 pybuiltin


julia> pybuiltin(:dict)(a=1,b=2)
Dict{Any,Any} with 2 entries:
  "b" => 2
  "a" => 1

julia> d = pycall(pybuiltin("dict"), Any, a=1, b=2)
PyObject {'b': 2, 'a': 1}

julia> typeof(d)
PyObject

# 利用 PyDict 轉換為 julia dict object
julia> julia_dictionary = PyDict{Symbol, Int64}(pycall(pybuiltin("dict"), Any, a=1, b=2))
PyDict{Symbol,Int64,true} with 2 entries:
  :b => 2
  :a => 1

julia> typeof(julia_dictionary)
PyDict{Symbol,Int64,true}

julia> julia_dictionary[:a]
1

# 產生一個 kw 參數的 function
julia> f(; a=0, b=0) = [10a, b]
f (generic function with 1 method)

# 以 dict 呼叫 function
julia> f(;julia_dictionary...)
2-element Array{Int64,1}:
 10
  2

Expressions


這是 metaprogramming 的功能,這是參考 LISP 的功能


首先說明 julia 如何 interprets a code


julia> code = "println(\"hello world \")"
"println(\"hello world \")"

julia> expression = Meta.parse(code)
:(println("hello world "))

julia> typeof(expression)
Expr

julia> expression.args
2-element Array{Any,1}:
 :println
 "hello world "

julia> expression.head
:call

julia> dump(expression)
Expr
  head: Symbol call
  args: Array{Any}((2,))
    1: Symbol println
    2: String "hello world "

產生 expression,用 eval 運算, :call 是 symbol,表示 head of the expression


julia> sample_expr = Expr(:call, +, 10, 20)
:((+)(10, 20))

julia> eval(sample_expr)
30

julia> sample_expr.args
3-element Array{Any,1}:
   +
 10
 20

將參數替換為 :x, :y 變數,也可以直接寫 x, y


julia> x = 10; y =10
10

julia> sample_expr = Expr(:call, +, :x, :y)
:((+)(x, y))

julia> sample_expr = Expr(:call, +, x, y)
:((+)(10, 10))

julia> eval(sample_expr)
20

也可以使用 $


julia> x = 10; y=10
10

julia> e = :($x + $y)
:(10 + 10)

julia> eval(e)
20

所以有 : 跟 $ 兩種方式可產生 Expr object


  • Using quotes(:) at runtime
  • Using dollar($) ar parse time

另外還有一個方式,是使用 quote 這個 keyword。quote 跟 : 的差別,是用 quote 可讓程式碼排列更好,比較容易實作


julia> quote
          30 * 100
       end
quote
    #= REPL[88]:2 =#
    30 * 100
end

julia> eval(ans)
3000

julia> :(30 * 100)
:(30 * 100)

julia> eval(ans)
3000

Macros


類似 function,但 function 使用 variables 為參數,而 macros 使用 expressions,並回傳 modified expressions,呼叫 macro 是用 @


macro NAME
    # some custom code
    # return modified expression
end

因為 REPL 建立的 macro 是在 Main module 裡面


julia> macro HELLO(name)
         :( println("Hello! ", $name))
       end
@HELLO (macro with 1 method)

julia> @HELLO("world")
Hello! world

julia> macroexpand(Main, :(@HELLO("world")))
:((Main.println)("Hello! ", "world"))



why metaprogramming?

metaprogramming 可省略很多重複的程式碼


for sym in [:foo, :bar, :baz]
    @eval function $(Symbol(sym))(n::Int64)
        for i in 1:n
            println( $(string(sym)) )
        end
    end
end

可這樣使用


foo(1)
bar(2)
baz(3)



for header in [:h1, :h2, :h3, :h4, :h5, :h6]
     @eval function $(Symbol(header))(text::String)
         println("<" * $(string(header))* ">"  * " $text " * "</" * $(string(header))* ">")
     end
 end

h1("Hello world!")
# <h1> Hello world! </h1>

h3("Hello world!")
# <h3> Hello world! </h3>



Built-in macros

以下是所有內建的 macros


julia> @
@MIME_str      @boundscheck    @edit           @html_str       @nospecialize   @text_str
@__DIR__       @cfunction      @elapsed        @inbounds       @polly          @threadcall
@__FILE__      @cmd            @enum           @info           @r_str          @time
@__LINE__      @code_llvm      @error          @inline         @raw_str        @timed
@__MODULE__    @code_lowered   @eval           @int128_str     @s_str          @timev
@__dot__       @code_native    @evalpoly       @isdefined      @show           @uint128_str
@allocated     @code_typed     @fastmath       @label          @simd           @v_str
@assert        @code_warntype  @functionloc    @less           @specialize     @view
@async         @debug          @generated      @macroexpand    @static         @views
@b_str         @deprecate      @gensym         @macroexpand1   @sync           @warn
@big_str       @doc            @goto           @noinline       @task           @which

  • @time


    可取得執行某一段程式的耗費時間


    julia> function recursive_sum(n)
              if n == 0
                  return 0
              else
                  return n + recursive_sum(n-1)
              end
           end
    recursive_sum (generic function with 1 method)
    
    julia> @time recursive_sum(10000)
      0.005359 seconds (3.22 k allocations: 183.158 KiB)
    50005000
  • @elapsed


    類似 @time,但只有回傳時間 in Float64


    julia> @elapsed recursive_sum(10000)
    3.0984e-5
    
    julia> @elapsed recursive_sum(10000)
    2.4597e-5
  • @show


    會回傳 expression


    julia> @show(println("hello world"))
    hello world
    println("hello world") = nothing
    
    julia> @show(:(println("hello world")))
    $(Expr(:quote, :(println("hello world")))) = :(println("hello world"))
    :(println("hello world"))
    
    julia> @show(:(3*2))
    $(Expr(:quote, :(3 * 2))) = :(3 * 2)
    :(3 * 2)
    
    julia> @show(3*2)
    3 * 2 = 6
    6
    
    julia> @show(Int64)
    Int64 = Int64
    Int64
  • @which


    如果有某個 function 有多個 methods,也就是 multiple dispatch 的功能,想知道會呼叫哪一個 method


    julia> function tripple(n::Int64)
              3n
           end
    tripple (generic function with 1 method)
    
    julia> function tripple(n::Float64)
              3n
           end
    tripple (generic function with 2 methods)
    
    julia> methods(tripple)
    # 2 methods for generic function "tripple":
    [1] tripple(n::Float64) in Main at REPL[11]:2
    [2] tripple(n::Int64) in Main at REPL[10]:2
    
    julia> @which tripple(10)
    tripple(n::Int64) in Main at REPL[10]:2
    
    julia> @which tripple(10.0)
    tripple(n::Float64) in Main at REPL[11]:2
  • @task


    類似 coroutine,用來產生一個 task,而不是直接執行


    julia> say_hello() = println("hello world")
    say_hello (generic function with 1 method)
    
    julia> say_hello_task = @task say_hello()
    Task (runnable) @0x0000000113ed9210
    
    julia> istaskstarted(say_hello_task)
    false
    
    julia> schedule(say_hello_task)
    hello world
    Task (queued) @0x0000000113ed9210
    
    julia> yield()
    
    julia> istaskdone(say_hello_task)
    true
  • @codellvm, @codelowered, @codetyped,@codenative, and @code_warntype


    瞭解 code 在 julia 中的所有形式


    function fibonacci(n::Int64)
       if n < 2
           n
       else 
           fibonacci(n-1) + fibonacci(n-2)
       end
    end
    
    fibonacci(n::Int64) = n < 2 ? n : fibonacci(n-1) + fibonacci(n-2)
    
    # 轉換為 single static assignment,每個變數只會被 assigned 一次,在使用變數前都會先定義
    @code_lowered fibonacci(10)
    
    # 
    @code_typed fibonacci(10)
    
    @code_warntype fibonacci(10)
    
    # 使用 LLVM C++ API 產生 LLVM intermediate representation
    @code_llvm fibonacci(10)
    
    # binary code in memory
    @code_native fibonacci(10)
    

Type introspection


首先定義新的 type: Student,產生兩個物件


struct Student
   name::String
   age::Int64
end

alpha = Student("alpha",24)

beta = Student("beta",25)

可檢查物件的資料型別,或是使用 isa 判斷是否為某個 function 產生的 type


julia> typeof(alpha)
Student

julia> isa(alpha, Student)
true

julia> alpha isa Student
true

reflection


可在 runtime 查詢物件的 attributes。在 julia 產生 function 後,就可以查詢 function 有幾個參數,有哪些 methods。


function calculate_quad(a::Int64,b::Int64,c::Int64,x::Int64)
   return a*x^2 + b*x + c
end

calculate_quad(1,2,3,4)

function calculate_quad(a::Int64,b::Int64,c::Int64,x::Float64)
   return a*x^2 + b*x + c
end

calculate_quad(1,2,3,4.75)

julia> methods(calculate_quad)
# 2 methods for generic function "calculate_quad":
[1] calculate_quad(a::Int64, b::Int64, c::Int64, x::Float64) in Main at REPL[38]:2
[2] calculate_quad(a::Int64, b::Int64, c::Int64, x::Int64) in Main at REPL[36]:2

julia> fieldnames(Student)
(:name, :age)

julia> Student.types
svec(String, Int64)

julia> typeof(Student.types)
Core.SimpleVector

References


Learning Julia