From d48b0ab7b654103e4a768008cb0bcdb6ab930e9d Mon Sep 17 00:00:00 2001 From: William Bell Date: Thu, 30 May 2024 12:46:25 +0100 Subject: [PATCH] add eval and potentially speed up variable access speeds when multi threading. fix bug in threading count --- src/built-ins.go | 1 + src/eval_function.go | 41 ++++++++++++++++++++++++++++++++++++++++ src/main.go | 8 +++----- src/map.go | 5 ++--- src/thread.go | 18 ++++++++---------- tests/multi_threading.ar | 14 ++++++++++++++ 6 files changed, 69 insertions(+), 18 deletions(-) create mode 100644 src/eval_function.go create mode 100644 tests/multi_threading.ar diff --git a/src/built-ins.go b/src/built-ins.go index 336f036..553cee8 100644 --- a/src/built-ins.go +++ b/src/built-ins.go @@ -19,6 +19,7 @@ func makeGlobal() ArObject { "client": builtinFunc{"client", ArSocketClient}, }) vars["infinity"] = infinity + vars["eval"] = builtinFunc{"eval", AReval} vars["map"] = builtinFunc{"map", func(a ...any) (any, ArErr) { if len(a) == 0 { return Map(anymap{}), ArErr{} diff --git a/src/eval_function.go b/src/eval_function.go new file mode 100644 index 0000000..8ceb1da --- /dev/null +++ b/src/eval_function.go @@ -0,0 +1,41 @@ +package main + +import "fmt" + +func AReval(a ...any) (any, ArErr) { + if len(a) < 1 || len(a) > 2 { + return nil, ArErr{TYPE: "Type Error", message: "expected 1 or 2 argument, got " + fmt.Sprint(len(a)), EXISTS: true} + } + var expression string + if typeof(a[0]) != "string" { + return nil, ArErr{TYPE: "Type Error", message: "expected string as first argument, got " + typeof(a[0]), EXISTS: true} + } + expression = ArValidToAny(a[0]).(string) + + // translate the expression + var code UNPARSEcode = UNPARSEcode{ + code: expression, + realcode: expression, + line: 0, + path: "eval", + } + translated, err := translate([]UNPARSEcode{code}) + if err.EXISTS { + return nil, err + } + + var scope ArObject + if len(a) == 2 { + if typeof(a[1]) != "map" { + return nil, ArErr{TYPE: "Type Error", message: "expected map as second argument, got " + typeof(a[1]), EXISTS: true} + } + scope = a[1].(ArObject) + } else { + scope = newscope() + } + + var stack stack = []ArObject{scope} + + // run the translated expression + return run(translated, stack) +} diff --git a/src/main.go b/src/main.go index ba422c0..47dac1d 100644 --- a/src/main.go +++ b/src/main.go @@ -10,8 +10,8 @@ var Args = os.Args[1:] type stack = []ArObject -const VERSION = "3.0.6" -const VERSION_NUM = 4 +const VERSION = "3.0.7" +const VERSION_NUM = 5 func newscope() ArObject { return Map(anymap{}) @@ -66,7 +66,5 @@ func main() { panicErr(runimeErr) os.Exit(1) } - if threadCount > 0 { - <-threadChan - } + threadChan.Wait() } diff --git a/src/map.go b/src/map.go index d035553..f272b82 100644 --- a/src/map.go +++ b/src/map.go @@ -114,10 +114,9 @@ func parseMap(code UNPARSEcode, index int, codelines []UNPARSEcode) (any, bool, }, true, ArErr{}, countIndex } -var mutex = sync.RWMutex{} -var listenersMutex = sync.RWMutex{} - func Map(m anymap) ArObject { + var mutex = sync.RWMutex{} + var listenersMutex = sync.RWMutex{} var currentID uint32 = 0 listeners := map[any]map[uint32]any{} obj := ArObject{ diff --git a/src/thread.go b/src/thread.go index 7f5307e..6b7fc66 100644 --- a/src/thread.go +++ b/src/thread.go @@ -2,10 +2,10 @@ package main import ( "fmt" + "sync" ) -var threadCount = 0 -var threadChan = make(chan bool) +var threadChan = sync.WaitGroup{} func ArThread(args ...any) (any, ArErr) { if len(args) != 1 { @@ -28,7 +28,7 @@ func ArThread(args ...any) (any, ArErr) { hasrun := false joined := false - var wg = make(chan bool) + var wg = sync.WaitGroup{} threadMap := Map(anymap{ "start": builtinFunc{"start", func(args ...any) (any, ArErr) { if hasrun { @@ -38,14 +38,12 @@ func ArThread(args ...any) (any, ArErr) { return nil, ArErr{TYPE: "Type Error", message: "Invalid number of arguments, expected 0, got " + fmt.Sprint(len(args)), EXISTS: true} } hasrun = true - threadCount++ + wg.Add(1) + threadChan.Add(1) go func() { resp, err = runCall(call{Callable: tocall, Args: []any{}}, nil, 0) - wg <- true - threadCount-- - if threadCount == 0 { - threadChan <- true - } + wg.Done() + threadChan.Done() }() return nil, ArErr{} }}, @@ -59,7 +57,7 @@ func ArThread(args ...any) (any, ArErr) { return nil, ArErr{TYPE: "Type Error", message: "Invalid number of arguments, expected 0, got " + fmt.Sprint(len(args)), EXISTS: true} } joined = true - <-wg + wg.Wait() return resp, err }}, }) diff --git a/tests/multi_threading.ar b/tests/multi_threading.ar new file mode 100644 index 0000000..875305d --- /dev/null +++ b/tests/multi_threading.ar @@ -0,0 +1,14 @@ +let mythread(threadID) = do + term.log(threadID, "start") + let mynumber = 10 + for (i from 0 to 1e4) do + mynumber += 1 + mynumber + return term.log(threadID, "done") + +let threads = [] +term.time("start") +for (i from 0 to 100) do + threads.append(thread(()=mythread(i))) + threads[i].start() +term.timeEnd("start") \ No newline at end of file