Julia控制流
异常处理
任务:
Julia中提供的控制流
- 复合表达式 : begin 和 (;)
- 条件求值 : if-elseif-else 和 ?: (ternary operator)
- 短路求值 : &&, || 和 chained comparisons
- 重复求值: 循环 : while 和 for
- 异常处理 : try-catch , error 和 throw
- 任务(也称为协程) : yieldto
复合表达式
begin块
代码语言:javascript复制z = begin
x = 1
y = 2
x y
end
>>3
(;)
链式
z = (x = 1; y = 2; x y)
这两种表示方式的值,都是最后一个表达式的值。
条件极值
代码语言:javascript复制if x < y
println("x is less than y")
elseif x > y
println("x is greater than y")
else
println("x is equal to y")
end
判断的条件必须是true
或false
中的一个
if 1
println("test...")
end
>>TypeError: non-boolean (Int64) used in boolean context
while循环
代码语言:javascript复制i = 5
while i <= 5
println(i)
i = 1
end
上面的循环用for循环写为
代码语言:javascript复制for i = 1:5
println(i)
end
for还可以遍历任意容器
代码语言:javascript复制for i in [1,2,3,4,5]
println(i)
end
for的其他用法
代码语言:javascript复制for i in "abcd"
println(i)
end
for i in 1:2:10
println(i)
end
for i in 10:-2:1
println(i)
end
[x^2 for x in 1:4]
[x^2 for x ∈ 1:5]
[(x, x^2) for x ∈ 1:5]
for (i,x) in enumerate(1:4:20)
println(i, " ", x)
end
collect(enumerate(1:4:20))
continue和break的用法跟其他语言基本一致,这里就不多讲了。
变量作用域
代码语言:javascript复制for i in 1:5
x = i
end
此时如果在for循环外面查看x的值,则会提示error,因为变量x只是for循环内部的。
如果想在for外部也使用x,则要写成
代码语言:javascript复制for i in 1:5
global x = i
end
如果我们在外部提前定义了x
代码语言:javascript复制x = 10
for i in 1:5
x = i
end
此时的x仍为10,因为for里面默认x是local的
异常处理
代码语言:javascript复制sqrt(-1)
>>DomainError with -1.0:
sqrt will only return a complex result if called with a complex argument. Try sqrt(Complex(x)).
Stacktrace:
[1] throw_complex_domainerror(::Symbol, ::Float64) at .math.jl:31
[2] sqrt at .math.jl:479 [inlined]
[3] sqrt(::Int64) at .math.jl:505
[4] top-level scope at In[4]:1
try
sqrt(-1)
catch
println("pass")
end
sqrt_second(x) = try
sqrt(x[2])
catch y
if isa(y, DomainError)
sqrt(complex(x[2], 0))
elseif isa(y, BoundsError)
sqrt(x)
end
end
finally语句 通常异常会导致程序提前退出,使得某些操作不能执行,关键字 finally 可以解决这样的问题,无论程序是怎样退出的,finally 语句总是会被执行。
代码语言:javascript复制f = open("file")
try
# operate on file f
finally
close(f)
end
可以将try
、catch
和finally
连起来使用,finally
在catch
处理完异常后执行。
任务(也称为协程)
被称为为对称协程、轻量级线程、协同多任务等。(与线程有区别,在后面的并行计算中会讲)
如果一个计算以任务的方式执行,那它就很可能会被其他任务中断,原先的任务在恢复后,会从被中断的地方继续工作,这种过程看似很像函数调用,但有两点不同:
- 任务切换不需要任何空间,因此可以完成任意数量任务的切换,而且无需考虑堆栈问题。
- 任务切换可以按照任何顺序来进行。
任务比较适合生产者-消费者模式,一个过程用来生产值,另一个用来消费值。消费者不能简单的调用生产者来得到值,因为两者的执行时间不一定协同。在任务中,两者则可以正常运行。
Julia中提供了Channel来解决生产者消费者的协同问题,其实Channel就是一个FIFO(first-in first-out)队列。使用put!
和take!
函数来具体实现。
function producer(c::Channel)
put!(c, "start")
for n=1:4
put!(c, 2n)
end
put!(c, "stop")
end
然后我们新建一个Channel组件,来消费数值。
代码语言:javascript复制chnl = Channel(producer)
take!(chnl)
>>"start"
take!(chnl)
>>2
take!(chnl)
>>4
take!(chnl)
>>6
take!(chnl)
>>8
take!(chnl)
>>"stop"
也可以使用for
循环的方式
for x in Channel(producer)
println(x)
end
>>start
2
4
6
8
sotp
在两次调用put!()
之间,生产者的执行是挂起的,此时由消费者接管控制。
任务的一个特性就是随着任务的结束,channel对象会自动关闭,无需人为干预。
把一般的函数放到task中:
代码语言:javascript复制function mytask(n)
for i=1:n
println(i)
end
end
taskHdl = @task mytask(10)
println(istaskdone(taskHdl))
schedule(taskHdl)
println(current_task())
println(istaskdone(taskHdl))
>>false
1
2
3
4
5
6
7
8
9
10
Task (runnable) @0x000000000d41eb30
true