更新

Ver 2.6では高負荷の状態でも正確に30秒間が測れるよう、ロジックを変更しました。

従来より高負荷の状態では瞬間最高速度が30打鍵を超えるといった報告をいただいていましたが、その問題を再現することが難しく解決できずにいました。今回、ユーザーさんが撮影されたプレイ動画がツイートされ、多くの方から情報をいただき、問題の再現・解決ができました。

同時に従来のロジックでは負荷のない状態でも0.3~0.9秒ほど長く打てていたことがわかりました。環境によってはそれよりも長い場合があるかもしれません。申し訳ございませんでした。

まとめ

  • 高負荷の状態で制限時間が大幅に伸びる問題は解決した。
  • 高負荷ではない通常の状態でも制限時間が0.3~0.9秒ほど延びていたことがわかった。これも解決した。
  • 文字入力やチート対策といったメイン処理と、定期的に実行されるsetIntervalのカウントダウン処理のタイミングが重なった際、どちらかの処理が完了しないと次の処理が始まらないことが原因。このときメイン処理が先に実行されていると、カウントダウン処理に遅延が生じる。
  • 通常の状態でも制限時間が延びていたのはVer 2.52から。期間にすると2019/9/15~2020/10/27まで。

従来のロジック

30秒間のカウントダウン処理にはJavascriptのsetIntervalを使っていました。100ミリ秒(0.1秒)ごとに処理を行い、これを10回繰り返すことで1秒、300回繰り返すことで30秒を計測していました。

なお、Javascript版の初回公開時(2016/10/29)はsetIntervalの間隔を1000ミリ秒(1秒)にしていましたが、チート対策などのためにVer 2.52(2019/9/15)から間隔を100ミリ秒に変更しました。

このロジックでは高負荷の状態だと100ミリ秒が正確に測れず300ミリ秒以上の遅延が生じることがあり、1秒が2秒にも3秒にもなることがありました。

新しいロジック

setIntervalで遅延が生じても経過時刻に影響がでないようにすべく、setIntervalの繰り返し回数ではなく、その処理のタイミングで時間を取得・比較することにしました。

具体的にはsetIntervalを行うたびにnew Date()で現在時刻をミリ秒で取得し、処理の始めに取得しておいた開始時刻と比較して経過時刻を算出します。さらにsetIntervalの間隔を10ミリ秒(0.01秒)にして、より精度を高めました。

結果、高負荷の状態でも30秒間での誤差を0.01秒未満にすることができました。ただし、この方法でも瞬間最高速度の異常値は回避できません。

そのためsetIntervalに100ミリ秒を超える遅延が3回以上発生すると強制終了することにしました。同一ブラウザでタブを切り替えた場合でも処理間隔が延びるため強制終了します。ご注意ください。

負荷のない状態での新しいロジックの確認

負荷のない状態で新しいロジックを試したところ、setIntervalを実行するたび遅延が生じることがある、ということに気がつきました。従来のロジックでは0.1秒あたり0.001~0.003秒の遅延となり、1秒だと0.01~0.03秒、30秒で0.3~0.9秒の遅延になります。

これはJavascriptのシングルスレッド処理とsetInterval/setTimeoutの仕様を正しく理解していなかったことに問題がありました。文字入力やチート対策といったメイン処理と、定期的に実行されるsetIntervalのカウントダウン処理のタイミングが重なった際、どちらかの処理が完了しないと次の処理が始まりません。このときメイン処理が先に実行されていると、カウントダウン処理が後回しにされ、数ミリ秒の遅延が生じることになります。

このあたりの理解がふわふわしており、理解が間違っていたらすみません。

おわび

動作確認が不十分でした。申し訳ございませんでした。

今回のロジック変更によりこれらすべての問題は解決しており、0.05秒ごとに1文字の入力(20打鍵/秒)があったとしても30秒間での誤差は0.01秒未満となります。

2019/9/15に更新したVer 2.52から、この問題が生じていました。それ以前のsetIntervalの処理間隔は1000ミリ秒(1秒)であったため、30秒間での遅延は0.03~0.09秒ほどで済んでいたものと思います。

「最近、なんだか速くなったなあ」と思われていたユーザーさんに対して申し訳なく思います。私自身、ずっと超えられずにいた300打鍵を達成したのが2019年10月のお題になりますので、Ver 2.52のアップデートとのタイミングが一致しています。本当に申し訳ございませんでした。

問題解決にあたり、スクリーンショットや動画、ロジックの変更案などをいただいたユーザーのみなさんにお礼申し上げます。ありがとうございました。以後気をつけますが、どうしても気がつかないところが今後もあるものと思います。何かおかしなところがありましたら、随時ご連絡いただけると助かります。

参考ページ

今回の問題解決にはこちらの記事を参考にさせていただきました。ありがとうございました。