Julia 中的任务和并发访问
Task and concurrent access in Julia
Julia 中的任务和并发访问
我想在 Julia 中实现对虚拟键盘的管理,每个键盘都与一个专用任务(或进程、线程...)相关联。
在 Ada 中,这是通过为这些虚拟键盘使用受保护类型的对象和扫描计算机键盘的任务来管理的,如以下代码示例所示。
这如何在 Julia 中实现? Julia 中并发访问控制的文档显然很差。
with Unchecked_Deallocation;
package Buffer is
N : constant := 128;
type Index is mod N;
type Char_Array is array (Index) of Character;
protected type Keyboard is
entry Put (X : in Character);
entry Get (X : out Character);
private
A : Char_Array;
In_Ptr, Out_Ptr : Index := 0;
Count : Integer range 0 .. N := 0;
end Keyboard;
type Keyboard_Ptr is access all Keyboard;
procedure Free is new Unchecked_Deallocation (Keyboard, Keyboard_Ptr);
end Buffer;
package body Buffer is
protected body Keyboard is
entry Put (X : in Character) when Count < N is
begin
A (In_Ptr) := X;
In_Ptr := In_Ptr + 1;
Count := Count + 1;
end Put;
entry Get (X : out Character) when Count > 0 is
begin
X := A (Out_Ptr);
Out_Ptr := Out_Ptr + 1;
Count := Count - 1;
end Get;
end Keyboard;
end Buffer;
task Keyboard_Handler;
task body Keyboard_Handler is
K0 : Character;
Available : Boolean := False;
-- Keyboard_Current : Keyboard_Ptr is defined at upper level
begin
loop
Get_Immediate (K0, Available);
if Available and then Character'Pos (K0) /= 0 then
Keyboard_Current.Put (K0);
end if;
delay 0.06;
end loop;
end Keyboard_Handler;
第一步是展示如何拦截特定的按键(例如:箭头、w、v)以及如何将它们传送到频道。以下在 Windows 上可以很好地为主进程提供键盘信息:
ch1 = Channel{String}(128)
function run(ch1::Channel)
while true
c1 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c1 == 224
c2 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c2 == 72
put!(ch1, "KEY UP")
elseif c2 == 80
put!(ch1, "KEY DOWN")
elseif c2 == 77
put!(ch1, "KEY RIGHT")
elseif c2 == 75
put!(ch1, "KEY LEFT")
elseif c2 == 81
put!(ch1, "ALT KEY DOWN")
elseif c2 == 73
put!(ch1, "ALT KEY UP")
end
elseif c1 == Int32('w')
put!(ch1, "w")
elseif c1 == Int32('v')
put!(ch1, "v")
end
end
end
buffer = Channel(run)
for x in buffer
println(x)
end
现在我想通过键盘输入来完成我选择的任务。可能与 :
using Distributed
addprocs(3)
function tache1(ch::Channel)
for x in ch
println("TACHE 1 :",x)
end
end
function tache2(ch::Channel)
for x in ch
println("TACHE 2 :",x)
end
end
buffer1 = Channel(tache1)
buffer2 = Channel(tache2)
ch1 = buffer1
function run()
while true
c1 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c1 == 224
c2 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c2 == 72
put!(ch1, "KEY UP")
elseif c2 == 80
put!(ch1, "KEY DOWN")
elseif c2 == 77
put!(ch1, "KEY RIGHT")
elseif c2 == 75
put!(ch1, "KEY LEFT")
elseif c2 == 81
put!(ch1, "ALT KEY DOWN")
elseif c2 == 73
put!(ch1, "ALT KEY UP")
end
elseif c1 == Int32('w')
ch1 = Channel(tache1)
elseif c1 == Int32('v')
ch1 = Channel(tache2)
end
end
end
f = @spawnat 1 run()
function t1()
for x in buffer1
println("11111 ",x)
end
end
function t2()
for x in buffer2
println("22222 ",x)
end
end
h1 = @spawnat 2 t1()
h2 = @spawnat 3 t2()
for x in buffer1
println(x)
end
但是没有用!可能是 Julia 无法做到 Ada 可以轻松做到的事情……?或者更可能是我对 Julia 的多任务方面的理解非常糟糕。
您在问题中添加了一些代码,所以我在此处添加了代码。
原来的例子在下面。
# This works and perhaps is what you wanted to do?
# I am unsure of some of the tasks you set up in the question's code.
CHAN1 = Channel{String}(0)
CHAN2 = Channel{String}(0)
function tache1()
while true
x = take!(CHAN1)
println("TACHE 1 :", x)
end
end
function tache2()
while true
x = take!(CHAN2)
println("TACHE 2 :", x)
end
end
function run()
try
println("Esc to exit.")
chan = CHAN1
while true
c1 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c1 == 224
c2 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c2 == 72
put!(chan, "KEY UP")
elseif c2 == 80
put!(chan, "KEY DOWN")
elseif c2 == 77
put!(chan, "KEY RIGHT")
elseif c2 == 75
put!(chan, "KEY LEFT")
elseif c2 == 81
put!(chan, "ALT KEY DOWN")
elseif c2 == 73
put!(chan, "ALT KEY UP")
end
elseif c1 == Int32('w')
chan = CHAN1
elseif c1 == Int32('v')
chan = CHAN2
elseif(c1 == 27)
close(CHAN1)
close(CHAN2)
exit(0)
else
println(Char(c1))
end
end
catch y
println("Exception caught: ", y)
exit(1)
end
end
@async run()
@async tache1()
@async tache2()
while true
sleep(0.05)
end
剪切---------------------------------------- ------------------------
这是一个使用 Gtk 库拦截 3 种不同 windows 击键的示例 (Julia 1.0)。您也可以将通道函数与对 _getch 的 Windows C 调用一起使用。
#(note: revised to show Channel usage)
using Gtk.ShortNames
function keypresswindow(chan)
# This code creates the Gtk widgets on the screen.
txt = "Type Y or N"
win = Window("Keypress Test", 250, 30) |> (Frame() |>
((vbox = Box(:v)) |> (lab = Label(txt))))
# this is the keystroke processing code, a function and a callback for the function.
function keycall(w, event)
ch = Char(event.keyval)
put!(chan, ch)
set_gtk_property!(lab,:label, ch in('n','N','y','Y') ? "You hit the $ch key." : txt)
end
Gtk.signal_connect(keycall, win, "key-press-event")
# this code sets up a proper exit when the widow is closed.
c = Condition()
endit(w) = notify(c)
Gtk.signal_connect(endit, win, :destroy)
Gtk.showall(win)
wait(c)
end
function reader(chan)
while true
try
c = take!(chan)
print(c)
catch
return
end
end
end
function inputwindows(chan, numwindows)
@async reader(chan)
println("starting input windows")
@sync(
for i in 1:numwindows
@async keypresswindow(chan)
end
)
println("finished")
end
const chan = Channel(1020)
inputwindows(chan, 3)
其实我的问题的解决方案不需要Channel。 Julia 中的任务只是协程这一简单事实保证了键盘访问不会发生冲突。在 Windows 平台上,通过键盘交互选择和驱动的 2 个任务的解决方案演示是:
function run1()
while true
c1 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c1 == 224
c2 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c2 == 72
println("KEY UP1")
elseif c2 == 80
println("KEY DOWN1")
elseif c2 == 77
println("KEY RIGHT1")
elseif c2 == 75
println("KEY LEFT1")
elseif c2 == 81
println("ALT KEY DOWN1")
elseif c2 == 73
println("ALT KEY UP1")
end
elseif c1 == Int32('w')
yieldto(tb)
end
end
end
function run2()
while true
c1 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c1 == 224
c2 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c2 == 72
println("KEY UP2")
elseif c2 == 80
println("KEY DOWN2")
elseif c2 == 77
println("KEY RIGHT2")
elseif c2 == 75
println("KEY LEFT2")
elseif c2 == 81
println("ALT KEY DOWN2")
elseif c2 == 73
println("ALT KEY UP2")
end
elseif c1 == Int32('w')
yieldto(ta)
end
end
end
ta = Task(run1)
tb = Task(run2)
yieldto(tb)
Julia 中的任务和并发访问
我想在 Julia 中实现对虚拟键盘的管理,每个键盘都与一个专用任务(或进程、线程...)相关联。
在 Ada 中,这是通过为这些虚拟键盘使用受保护类型的对象和扫描计算机键盘的任务来管理的,如以下代码示例所示。
这如何在 Julia 中实现? Julia 中并发访问控制的文档显然很差。
with Unchecked_Deallocation;
package Buffer is
N : constant := 128;
type Index is mod N;
type Char_Array is array (Index) of Character;
protected type Keyboard is
entry Put (X : in Character);
entry Get (X : out Character);
private
A : Char_Array;
In_Ptr, Out_Ptr : Index := 0;
Count : Integer range 0 .. N := 0;
end Keyboard;
type Keyboard_Ptr is access all Keyboard;
procedure Free is new Unchecked_Deallocation (Keyboard, Keyboard_Ptr);
end Buffer;
package body Buffer is
protected body Keyboard is
entry Put (X : in Character) when Count < N is
begin
A (In_Ptr) := X;
In_Ptr := In_Ptr + 1;
Count := Count + 1;
end Put;
entry Get (X : out Character) when Count > 0 is
begin
X := A (Out_Ptr);
Out_Ptr := Out_Ptr + 1;
Count := Count - 1;
end Get;
end Keyboard;
end Buffer;
task Keyboard_Handler;
task body Keyboard_Handler is
K0 : Character;
Available : Boolean := False;
-- Keyboard_Current : Keyboard_Ptr is defined at upper level
begin
loop
Get_Immediate (K0, Available);
if Available and then Character'Pos (K0) /= 0 then
Keyboard_Current.Put (K0);
end if;
delay 0.06;
end loop;
end Keyboard_Handler;
第一步是展示如何拦截特定的按键(例如:箭头、w、v)以及如何将它们传送到频道。以下在 Windows 上可以很好地为主进程提供键盘信息:
ch1 = Channel{String}(128)
function run(ch1::Channel)
while true
c1 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c1 == 224
c2 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c2 == 72
put!(ch1, "KEY UP")
elseif c2 == 80
put!(ch1, "KEY DOWN")
elseif c2 == 77
put!(ch1, "KEY RIGHT")
elseif c2 == 75
put!(ch1, "KEY LEFT")
elseif c2 == 81
put!(ch1, "ALT KEY DOWN")
elseif c2 == 73
put!(ch1, "ALT KEY UP")
end
elseif c1 == Int32('w')
put!(ch1, "w")
elseif c1 == Int32('v')
put!(ch1, "v")
end
end
end
buffer = Channel(run)
for x in buffer
println(x)
end
现在我想通过键盘输入来完成我选择的任务。可能与 :
using Distributed
addprocs(3)
function tache1(ch::Channel)
for x in ch
println("TACHE 1 :",x)
end
end
function tache2(ch::Channel)
for x in ch
println("TACHE 2 :",x)
end
end
buffer1 = Channel(tache1)
buffer2 = Channel(tache2)
ch1 = buffer1
function run()
while true
c1 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c1 == 224
c2 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c2 == 72
put!(ch1, "KEY UP")
elseif c2 == 80
put!(ch1, "KEY DOWN")
elseif c2 == 77
put!(ch1, "KEY RIGHT")
elseif c2 == 75
put!(ch1, "KEY LEFT")
elseif c2 == 81
put!(ch1, "ALT KEY DOWN")
elseif c2 == 73
put!(ch1, "ALT KEY UP")
end
elseif c1 == Int32('w')
ch1 = Channel(tache1)
elseif c1 == Int32('v')
ch1 = Channel(tache2)
end
end
end
f = @spawnat 1 run()
function t1()
for x in buffer1
println("11111 ",x)
end
end
function t2()
for x in buffer2
println("22222 ",x)
end
end
h1 = @spawnat 2 t1()
h2 = @spawnat 3 t2()
for x in buffer1
println(x)
end
但是没有用!可能是 Julia 无法做到 Ada 可以轻松做到的事情……?或者更可能是我对 Julia 的多任务方面的理解非常糟糕。
您在问题中添加了一些代码,所以我在此处添加了代码。 原来的例子在下面。
# This works and perhaps is what you wanted to do?
# I am unsure of some of the tasks you set up in the question's code.
CHAN1 = Channel{String}(0)
CHAN2 = Channel{String}(0)
function tache1()
while true
x = take!(CHAN1)
println("TACHE 1 :", x)
end
end
function tache2()
while true
x = take!(CHAN2)
println("TACHE 2 :", x)
end
end
function run()
try
println("Esc to exit.")
chan = CHAN1
while true
c1 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c1 == 224
c2 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c2 == 72
put!(chan, "KEY UP")
elseif c2 == 80
put!(chan, "KEY DOWN")
elseif c2 == 77
put!(chan, "KEY RIGHT")
elseif c2 == 75
put!(chan, "KEY LEFT")
elseif c2 == 81
put!(chan, "ALT KEY DOWN")
elseif c2 == 73
put!(chan, "ALT KEY UP")
end
elseif c1 == Int32('w')
chan = CHAN1
elseif c1 == Int32('v')
chan = CHAN2
elseif(c1 == 27)
close(CHAN1)
close(CHAN2)
exit(0)
else
println(Char(c1))
end
end
catch y
println("Exception caught: ", y)
exit(1)
end
end
@async run()
@async tache1()
@async tache2()
while true
sleep(0.05)
end
剪切---------------------------------------- ------------------------
这是一个使用 Gtk 库拦截 3 种不同 windows 击键的示例 (Julia 1.0)。您也可以将通道函数与对 _getch 的 Windows C 调用一起使用。
#(note: revised to show Channel usage)
using Gtk.ShortNames
function keypresswindow(chan)
# This code creates the Gtk widgets on the screen.
txt = "Type Y or N"
win = Window("Keypress Test", 250, 30) |> (Frame() |>
((vbox = Box(:v)) |> (lab = Label(txt))))
# this is the keystroke processing code, a function and a callback for the function.
function keycall(w, event)
ch = Char(event.keyval)
put!(chan, ch)
set_gtk_property!(lab,:label, ch in('n','N','y','Y') ? "You hit the $ch key." : txt)
end
Gtk.signal_connect(keycall, win, "key-press-event")
# this code sets up a proper exit when the widow is closed.
c = Condition()
endit(w) = notify(c)
Gtk.signal_connect(endit, win, :destroy)
Gtk.showall(win)
wait(c)
end
function reader(chan)
while true
try
c = take!(chan)
print(c)
catch
return
end
end
end
function inputwindows(chan, numwindows)
@async reader(chan)
println("starting input windows")
@sync(
for i in 1:numwindows
@async keypresswindow(chan)
end
)
println("finished")
end
const chan = Channel(1020)
inputwindows(chan, 3)
其实我的问题的解决方案不需要Channel。 Julia 中的任务只是协程这一简单事实保证了键盘访问不会发生冲突。在 Windows 平台上,通过键盘交互选择和驱动的 2 个任务的解决方案演示是:
function run1()
while true
c1 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c1 == 224
c2 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c2 == 72
println("KEY UP1")
elseif c2 == 80
println("KEY DOWN1")
elseif c2 == 77
println("KEY RIGHT1")
elseif c2 == 75
println("KEY LEFT1")
elseif c2 == 81
println("ALT KEY DOWN1")
elseif c2 == 73
println("ALT KEY UP1")
end
elseif c1 == Int32('w')
yieldto(tb)
end
end
end
function run2()
while true
c1 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c1 == 224
c2 = ccall((:_getch, "msvcrt.dll "), Int32,())
if c2 == 72
println("KEY UP2")
elseif c2 == 80
println("KEY DOWN2")
elseif c2 == 77
println("KEY RIGHT2")
elseif c2 == 75
println("KEY LEFT2")
elseif c2 == 81
println("ALT KEY DOWN2")
elseif c2 == 73
println("ALT KEY UP2")
end
elseif c1 == Int32('w')
yieldto(ta)
end
end
end
ta = Task(run1)
tb = Task(run2)
yieldto(tb)