Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

非同期関数でローカル変数が壊れる問題 #1758

Open
kujirahand opened this issue Oct 17, 2024 · 6 comments
Open

非同期関数でローカル変数が壊れる問題 #1758

kujirahand opened this issue Oct 17, 2024 · 6 comments

Comments

@kujirahand
Copy link
Owner

kujirahand commented Oct 17, 2024

https://nadesi.com/cgi/kaizen3/index.php?m=thread&threadid=92 より

v3.6.22でも似た感じのが発生しています
ローカル変数がundefinedになる

//再現 (v3.6.22)
!インデント構文
0.1秒後には
 Aとは変数 = 「A」
 関数A
 Aを表示 //→undefined

●関数A
 Bとは変数 = 「B」
 関数B
 Bを表示 //→undefined

●関数B
 もし0ならば
  (1/30)秒待つ //(待たない)

ちなみに関数Bで待った場合「B」は表示されます


https://nadesi.com/cgi/kaizen3/index.php?m=thread&threadid=94 より

//-------ここから
●test1():
 xとは変数= 1
 1秒待つ
 xを表示
●test2():
 xとは変数= 2
 1秒待つ
 xを表示

0.1秒後には:
 test1
0.5秒後には:
 test2
//-------ここまで

実行結果
・v3.5.1(期待する動作)
1
2

・v3.6.1
2
2

・v3.6.25
2
undefined

@kujirahand kujirahand changed the title 未定義の関数がasyncFnだったとき、関数の定義前でその関数を使うと挙動がおかしくなる問題 後方で宣言した関数がasyncFnだったとき、その関数が正しく実行できない問題 Oct 17, 2024
@kujirahand
Copy link
Owner Author

kujirahand commented Oct 17, 2024

上記サンプルの「には」構文を、関数定義の末尾に持っていくと問題なく実行できます。
「には」構文(無名関数)を宣言する時点で、その関数が非同期かどうかが分かっていないのが問題となっています。

理由ですが、ある関数Cで参照した関数Aから呼び出している関数Bが非同期(asyncFn)だったとき、その関数を呼び出す関数Cを非同期で実行する必要があります。

根本的な解決案としては、なでしこのユーザー関数をすべて非同期関数(asyncFn)であると仮定するしかありません。
実行速度が遅くなるデメリットがありますが。

そこで下記の2つの解決作があります。

  • (1) なでしこの関数定義もasyncを明示できるような機能をつける
  • (2) なでしこのユーザー関数を問答無用でasyncにしてしまう

@kujirahand
Copy link
Owner Author

kujirahand commented Oct 17, 2024

ちょっと悩むけど、ユーザーにとって、変換され実行される時の関数がasyncかどうかはあまり問題ではないと思うので、上記(2)を採用するのが濃厚かも…。

@kujirahand
Copy link
Owner Author

ここに来て、以下のユーザー関数を全てaysncにする案が浮上中です。
実行速度は多少落ちるものの、正しい結果が出ないよりは、断然良いと考えられます。

(2) なでしこのユーザー関数を問答無用でasyncにしてしまう

@kujirahand
Copy link
Owner Author

kujirahand commented Oct 31, 2024

非同期関数では、関数の呼び出し中に、別の関数の呼び出しが掛かるので、同期的に実行する関数ではあり得ない、ローカル関数の書き換え処理が行われることが原因です。

https://nadesi.com/cgi/kaizen3/index.php?m=log&logid=344
では、現象が指摘されていますが、
非同期関数の場合、PUSHとPOPがかみ合わない場面があります。
そのため、関数の呼び出し時に番号を付けた上で、ローカル変数Nをスタックに載せ、関数の最後にローカル変数Nをポップ(削除)する仕組みが必要になります。

「秒待つ」の前後に変数の値を出力するコードを作って実行してみると、現象がよく分かります。

●test1():
 「test1:begin」と表示
 xとは変数= 1
 ??「test1:x={x}」
 1秒待つ
 ??「test1:x={x}」
 「test1:end」と表示
●test2():
 「test2:begin」と表示
 xとは変数= 2
 ??「test2:x={x}」
 1秒待つ
 ??「test2:x={x}」
 「test2:end」と表示

0.1秒後には:
  ??「には1:begin」
 test1
 ??「には1:end」

0.5秒後には:
 ??「には2:begin」
 test2
 ??「には2:end」

つまり、これを解決するには、非同期関数の呼び出すごとに、ローカル変数の値を待避し、呼び出し後に戻す処理が必要なことが必要です。

最初の例を整理したもの

●関数Aとは:
 Aとは変数 = 「A」
 関数B // 待たない?
 "関数A:{A}"を表示 //→undefined

●関数Bとは:
 ??「関数B:before」
 1秒待つ //(待たない)
 ??「関数B:after」

0.1秒後には:
 Lとは変数 = 「L」
 関数A
 "L={L}"を表示 //→undefined

@kujirahand
Copy link
Owner Author

全てのユーザー関数を非同期にするなら、タイマーやDOM系のイベントも全部非同期で呼び出す必要がある...うーむ

@kujirahand kujirahand changed the title 後方で宣言した関数がasyncFnだったとき、その関数が正しく実行できない問題 非同期関数におけるローカル変数の問題 Nov 1, 2024
@kujirahand kujirahand changed the title 非同期関数におけるローカル変数の問題 非同期関数でローカル変数が壊れる問題 Nov 1, 2024
kujirahand added a commit that referenced this issue Nov 1, 2024
非同期関数でローカル変数が壊れる問題を修正 #1758
@kujirahand
Copy link
Owner Author

kujirahand commented Nov 1, 2024

まだ完全な修正には至っていません。引き続き問題を観察します。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant