モバイルアプリのユーザーがWebSocketを使用して接続しているWebアプリケーションがあります。サーバーには、時間内に変更できるデータAがあります。また、クライアント(モバイルアプリ)には、時間内に変更できるデータBがあります。
ユーザーがWebSocketを使用してサーバーにメッセージ(データDを取得する要求)を送信する場合、ユーザーデータBを実行してデータCを生成し、次にデータDを生成するときにループを適用する必要があります。この場合、2つのオプションが見つかりました。
(詳細:データを生成するため、Dにはいくつかのデータベース操作があるため、クライアントはモバイルアプリでデータを生成できません)
1つ目:ユーザーが毎回メッセージ(リクエスト)を送信するときに、サーバー上のサーバーデータAとユーザーデータBにネストされたループを適用できます。操作には2つのネストされたループがあり、時間計算量はO(A * B)です。ループの後、データDを生成するためのデータCがあります。
擬似コード:
function generateC () {
var C = []
for (let i = 0; i < A.length; i++) {
for (let j = 0; j < B.length; j++) {
if (A[i] == B[j]) {
C.Push(A[i])
}
}
}
generateD(C)
}
2番目:データを圧縮した後、サーバーデータAをクライアントに送信できます。次に、クライアントはループして独自のデータBをデータAに適用し、データCを生成します。この場合、サーバーのロード時間の複雑さを考慮すると、O(N) Nは文字の長さだと思います。
擬似コード:
var compressedA = gzip.compress(A)
socket.to("userX").emit("C", compressedA)
socket.on("C", function (C) {
generateD(C)
})
また、2番目の方法では、帯域幅でネットワークトラフィックを作成します。ネットワーク操作はCPU操作よりも費用がかかると思います。
したがって、サーバーに350.000人のアクティブユーザーがいる場合は、それを行う価値がありますか?
設定された共通部分を計算しています。二次時間ではなく線形時間でそれを非常に迅速に実行したい場合、追加のブールフィールド(または予備のビットが手元にある場合はビットフィールド):
var C = [];
// Mark each element in A.
for (let i = 0; i < A.length; i++) {
A[i].traversed = true;
}
// Look for elements in B that were marked above.
for (let i = 0; i < B.length; i++) {
// If B[i] was marked by the above loop (meaning element
// was found in both A and B), add it to C.
if (B[i].traversed) {
C.Push(B[i]);
B[i].traversed = false;
}
}
// C now contains the set intersection.
クライアントに計算させるのではなく、サーバー上でこのようにすることをお勧めします。このように線形時間で実行するとボトルネックになるとは思えませんが、それ以外の場合はさらにマイクロ最適化の余地があります。