varinfo()方法会列出所有当前存储的变量和模块。
JUlia中的很多语法和REPL的用法都跟matlab很像,比如上一次的结果用ans表示
julia> x = 1
1
julia> ans + 1
2
可以输入`+符号名称的方式来输入更多的Unicode数学字符,如\alpha后按tab键就会出现α的字符。
变量名尽量小写
类型和模块名首字母大写,单词间使用驼峰式分隔
在几个单词不易区分时才以分隔,一般不鼓励使用下划线
函数名和宏名使用小写字母,不使用下划线
修改参数的函数结尾使用!,这样的函数被称为mutating functions或in-place functions
查看某种进制类型的最大最小值:
(typemin(Int32), typemax(Int32))
>>(-2147483648, 2147483647)
typemax(Int64)+1
>>-9223372036854775808
简单的结构体:
和字典结构对比:
使用pair:
变量类型:
抽象类型不能被实例化,我们前面讲到的Int64/Float64等都是抽象类型的具体类型,抽象类型不能直接使用,类似于C++中的抽象类。
抽象类型的定义方法如下:
abstract type «name» end abstract type «name» <: «supertype» end
第二行中的<:表示新声明的抽象类型是后面类型的子类型。
如果没有给出父类型,则默认为Any。
抽象类型有:
abstract type Number end
abstract type Real <: Number end
abstract type AbstractFloat <: Real end
abstract type Integer <: Real end
abstract type Signed <: Integer end
abstract type Unsigned <: Integer end
Integer <: Number
>>true
Integer <: AbstractFloat
>>false
向量运算,跟MATLAB的操作完全相同,比如向量的点乘,就是说对向量的元素一一操作
[1,2,3].*3
>>3-element Array{Int64,1}:
3
6
9
比较运算,支持链式比较
1 <= 2 <= 3 == 3 <=5 >4 >=2
>>true
常用的数学函数
# 进位函数
round(x) #四舍五入
floor(x) #向下取整
ceil(x) #向上取整
trunc(x) #trunc是直接砍掉小数,在正数的时候trunc跟floor一样,负数时跟ceil一样
# 除法函数
div(x,y) #取模
fld(x,y) #取小于结果的最大整数
cld(x,y) #取大于结果的最小整数
rem(x,y) #取余
mod(x,y)
mod1(x,y1) #如果x是y的整数倍,则返回y,不会返回余数
mod2pi(x) #对2pi取余
divrem(x,y) #返回取模的值和取余的值
fldmod(x,y) #返回取小于x的最大整数和取余的值
gcd(x,y...) #最大公约数
lcm(x,y...) #最小公倍数
# 符号函数
abs(x) #求模
abs2(x) #求平方
sign(x) #取符号
signbit(x) #正数返回false,负数返回true
copysign(x,y) #返回x * sign(y)
flipsign(x,y) #返回x * sign(y) * -1
# 开根号 log
sqrt(x) #开根号
cbrt(x) #开三次根
hypot(x,y) #sqrt(x^2 + y^2)
exp(x) #e^x
expm1(x) #e^-x
ldexp(x,n) #x^n
log(x) #loge(x)
log(b,x) #logb(x)
log2(x) #log2(x)
log10(x) #log10(x)
log1p(x) #loge(1+x)
# 三角函数
sin cos tan cot sec csc
sinh cosh tanh coth sech csch
asin acos atan acot asec acsc
asinh acosh atanh acoth asech acsch
sinc cosc
x = ones(2,3)
y = zeros(2,3)
z = [x y]
>>2×6 Array{Float64,2}:
1.0 1.0 1.0 0.0 0.0 0.0
1.0 1.0 1.0 0.0 0.0 0.0
相当于hcat(x,y)
ndims(z)
>>2
z = [x,y]
>>2-element Array{Array{Float64,2},1}:
[1.0 1.0 1.0; 1.0 1.0 1.0]
[0.0 0.0 0.0; 0.0 0.0 0.0]
ndims(z)
>>1
[x;y]
>>4×3 Array{Float64,2}:
1.0 1.0 1.0
1.0 1.0 1.0
0.0 0.0 0.0
0.0 0.0 0.0
相当于vcat(x,y)
ndims(z)
>>2
最后的|>相当于管道。下面是个网红自动问答系统:
方法重载:
多重分派
分派就是指根据变量的类型选择相应的方法,单分派指的是指根据第一个参数类型去选择方法。
下面我们举一个Python中的例子,Python因为在函数定义时是不知道参数类型的,所以一般没有单分派;但Python中提供了单分派的修饰符,可以实现单分派的功能。
from functools import singledispatch
@singledispatch
def func(arg, verbose=False):
print('initial...\n')
@func.register(int)
def _(arg, verbose=False):
print(arg)
func(1)
>>1
func(2.3)
>>initial...
Julia中提供的控制流
复合表达式 : begin 和 (
条件求值 : if-elseif-else 和 ?: (ternary operator)
短路求值 : &&, || 和 chained comparisons
重复求值: 循环 : while 和 for
异常处理 : try-catch , error 和 throw
任务(也称为协程) : yieldto
在程序的最开始,加上push!(LOAD_PATH, “.”),可以加在自定义模块。
模块中的export是将这函数导出来,这样就可以直接使用。
协程也称为任务,如果一个计算以任务的方式执行,那它就很可能会被其他任务中断,原先的任务在恢复后,会从被中断的地方继续工作,这种过程看似很像函数调用,但有两点不同:1)任务切换不需要任何空间,因此可以完成任意数量任务的切换,而且无需考虑堆栈问题。2)任务切换可以按照任何顺序来进行。
任务比较适合生产者-消费者模式,一个过程用来生产值,另一个用来消费值。消费者不能简单的调用生产者来得到值,因为两者的执行时间不一定协同。在任务中,两者则可以正常运行。Julia中提供了Channel来解决生产者消费者的协同问题,其实Channel就是一个FIFO(first-in first-out)队列。使用put!和take!(或是fetch,不删除)函数来具体实现。任务的一个特性就是随着任务的结束,channel对象会自动关闭,无需人为干预。
如果一个 Channel 是空的,读取的 task(即执行 take! 的task)会被阻塞直到有新的数据准备好了;如果一个 Channel 是满的,那么写入的 task(即执行 put! 的 task)则会被阻塞,直到 Channel 有空余。在控制台里面表现为堵塞住,无法继续执行命令
isready 可以用来检查一个 channel 中是否有已经准备好的元素,而等待一个元素准备好 则用 wait
一个 Channel 一开始处于开启状态,也就是说可以被 take! 读取和 put! 写入。close 会关闭一个 Channel,对于一个已经关闭的 Channel,put! 会失败
使用Threads.nthreads()查看当前的线程数,默认是启动一个线程。
使用export JULIA_NUM_THREADS=4(Linux OSX)或set JULIA_NUM_THREADS=4(Windows)来设置启动4个线程。当我们要在Jupyter中使用多个线程时,可以在Julia的运行目录中下打开命令行,先设置线程数,再启动Julia。
其中Ref和[]分别是取地址和引用。
多进程也叫多核心或者分布式处理,就是用一个CPU的多个核心或者多个CPU进行编程。使用julia -p n启动多进程,也可以进入后添加。
Julia 中的分布式编程基于两个基本概念:远程引用(remote references)和远程调用(remote calls)。远程引用是一个对象,任意一个进程可以通过它访问存储在某个特定进程上的对象。远程调用指是某个进程发起的执行函数的请求,该函数会在另一个(也可能是同一个)进程中执行。
远程引用有两种类型:Future 和 RemoteChannel。
一次远程调用会返回一个 Future 作为结果。
远程调用会立即返回;也就是说,执行远程调用的进程接下来会继续执行下一个操作,而远程调用则会在另外的进程中进行。你可以通过对返回的 Future 执行 wait 操作来等待远程调用结束,然后用 fetch 获取结果。
对于 RemoteChannel 而言,它可以被反复写入。
例如,多个进程可以通过引用同一个远程 Channel 来协调相互之间的操作。
每个进程都有一个对应的 id,提供 Julia 交互环境的进程的 id 永远是1。我们把用来执行并行任务的进程称为 “worker”,假如总共只有一个进程,那么进程1就被认为是 worker,否则,除了进程1以外的进程都称作 worker。