5 Julia控制

2020-06-30 14:27:23 浏览数 (1)

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

(;)链式

代码语言:javascript复制
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

判断的条件必须是truefalse中的一个

代码语言:javascript复制
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

可以将trycatchfinally连起来使用,finallycatch处理完异常后执行。

任务(也称为协程)

被称为为对称协程、轻量级线程、协同多任务等。(与线程有区别,在后面的并行计算中会讲)

如果一个计算以任务的方式执行,那它就很可能会被其他任务中断,原先的任务在恢复后,会从被中断的地方继续工作,这种过程看似很像函数调用,但有两点不同:

  1. 任务切换不需要任何空间,因此可以完成任意数量任务的切换,而且无需考虑堆栈问题。
  2. 任务切换可以按照任何顺序来进行。

任务比较适合生产者-消费者模式,一个过程用来生产值,另一个用来消费值。消费者不能简单的调用生产者来得到值,因为两者的执行时间不一定协同。在任务中,两者则可以正常运行。

Julia中提供了Channel来解决生产者消费者的协同问题,其实Channel就是一个FIFO(first-in first-out)队列。使用put!take!函数来具体实现。

代码语言:javascript复制
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循环的方式

代码语言:javascript复制
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

0 人点赞