質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
アーキテクチャ

アーキテクチャとは、情報システム(ハードウェア、OS、アプリケーション、ネットワーク等)の設計方法、設計思想、設計思想に基づいて構築されたシステム構造をアーキテクチャと呼びます

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

Q&A

1回答

344閲覧

[クラス設計] 時間のかかる処理を逐次的に行いたい

退会済みユーザー

退会済みユーザー

総合スコア0

アーキテクチャ

アーキテクチャとは、情報システム(ハードウェア、OS、アプリケーション、ネットワーク等)の設計方法、設計思想、設計思想に基づいて構築されたシステム構造をアーキテクチャと呼びます

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

0グッド

0クリップ

投稿2020/09/03 21:49

編集2020/09/04 09:03

前提・実現したいこと

入力データA[]をデータB[]に、さらにデータB[]をデータC[]に変換して、最終的にC[]を出力するという処理を行いたいです。ここで条件は以下の通りです。

  • 開発はTypeScriptで行う
  • データのサイズは大きく変換処理にも時間がかかるため、非同期で行う (実際はWebWorkerを用いる)
  • ユーザーは変換処理中に関わらず任意のタイミングでデータAを何個でも入力することができる
  • 処理順を保証する必要がある (入力順と出力順が同じ)
  • データはいくつかまとめて処理をする (ex. 1000個のAを入力すると、100個ずつに分割されて順番に処理される)
  • 変換ABが全て終わってから変換BCを行うのではなく、例えば変換ABが100個終わったら変換BCを100個...と逐次的に行う (データAの最初の入力時からデータCの最初の出力までのレスポンスをできるだけ短くしたいため)
  • 変換BCが処理されている間にも変換ABを処理したい

このような場合、クラス設計(アーキテクチャ?)はどのようにしたら良いのでしょうか。将来的に機能の追加・修正が行われるため、できるだけ保守性の高いコードにしたいと考えています。

次の方法はどうか

初心者ながら次のような方法を考えたのですが、問題点などありますでしょうか。
継承の必要性についても知りたいです。

こちらにもコードを記載しています。Playground

TypeScript

1// アウトプットのあるノード 2interface ISourceNode<Out> { 3 connect(nextNode: IDestinationNode<Out>): void 4} 5 6// インプットのあるノード 7interface IDestinationNode<In> { 8 post(data: In[]): void 9} 10 11interface IConverterNode<In, Out> extends ISourceNode<Out>, IDestinationNode<In> { 12} 13 14// データInを受け取ってOutに変換するような基底クラス 15class ConverterNode<In, Out> implements IConverterNode<In, Out> { 16 private queue: In[] = [] 17 private isConverting = false // 変換処理中か 18 private batchSize: number // まとめて送るデータの数 19 private nextNode!: IDestinationNode<Out> 20 21 constructor(batchSize: number) { 22 this.batchSize = batchSize 23 } 24 25 // ノードを繋げる 26 connect(nextNode: IDestinationNode<Out>) { 27 this.nextNode = nextNode 28 } 29 30 // データTを受け取る 31 post(data: In[]): void { 32 this.queue.push(...data); // 受け取ったデータをキューに保持 33 34 // 変換中でなければ変換を開始する (順序を保証するため) 35 if (!this.isConverting && this.queue.length >= this.batchSize) { 36 const batch = this.queue.splice(0, this.batchSize) 37 this.isConverting = true 38 this.convert(batch) 39 } 40 } 41 42 // 変換処理を行う 43 protected convert(data: In[]): void { 44 } 45 46 // 変換されたデータを次のノード(IConverterNodeまたはIDestinationNode)に送る 47 protected converted(data: Out[]) { 48 this.nextNode.post(data) 49 50 // キューにまだ変換できるデータが存在するならconvertする 51 if (this.queue.length >= this.batchSize) { 52 const batch = this.queue.splice(0, this.batchSize) 53 this.convert(batch) 54 } else { 55 this.isConverting = false 56 } 57 } 58}

TypeScript

1type A = number 2type B = number 3 4// データAをデータBに変換するクラス 5class ABConverter extends ConverterNode<A, B> { 6 constructor(batchSize: number) { 7 super(batchSize) 8 } 9 10 // 変換処理を行う 11 protected convert(data: A[]): void { 12 new Promise<B[]>(resolve => { 13 // 何かしらの重い処理 14 setTimeout(() => { 15 resolve(data.map(a => a * 2)) 16 }, Math.random()*100) 17 }).then(dataB => { 18 // 変換されたらconvertedを呼ぶ 19 this.converted(dataB) 20 }) 21 } 22} 23 24// 入力ノード 25class SourceNode implements ISourceNode<A> { 26 private nextNode!: IDestinationNode<B> 27 28 connect(nextNode: IDestinationNode<A>) { 29 this.nextNode = nextNode 30 } 31 32 // データをConverterに送信 33 send(data: A[]) { 34 this.nextNode.post(data) 35 } 36} 37 38// 出力ノード (変換されたデータCがここにたどり着く) 39class DestinationNode implements IDestinationNode<B> { 40 post(data: B[]) { 41 console.log(data) 42 } 43} 44 45const source = new SourceNode() 46const ab = new ABConverter(3) 47const ab2 = new ABConverter(3) 48const dest = new DestinationNode() 49 50// source -> ab -> ab2 -> dest とデータが流れる 51source.connect(ab) 52ab.connect(ab2) 53ab2.connect(dest) 54 55source.send([1, 2, 3, 4, 5, 6])

このコードの場合、入力[1, 2, 3, 4, 5, 6][1, 2, 3] [4, 5, 6]に分割し、それぞれに対して各要素を2倍するという変換を2回施しているため、コンソールには

[4, 8, 12] [16, 20, 24]

と表示されます。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2020/09/03 22:28

当該のコードを実行するのはブラウザ内ですか?サーバサイドですか?それとも、どちらでもない環境でしょうか?
退会済みユーザー

退会済みユーザー

2020/09/03 22:43

ブラウザ内です
退会済みユーザー

退会済みユーザー

2020/09/04 09:46

ブラウザ内でやるなら、好きにやればいいのではないかと思いますが、c○in-hiveみたいな事件とかにはならないようにお願いしますね。何をやるにせよ、入出力と目的くらいは具体的に説明しないと設計し始めることも無理ではないかと思いますよ。今分かってるのはWebWorkerで並列実行してもいいってことだけなので。
guest

回答1

0

A→B→Cの作業は直列の処理なので非同期化はこんなんです

A(A1,A2,A3)→B(B1,B2,B3)→Cのような各処理分割できるなら可能性はあります

投稿2020/09/04 01:01

yambejp

総合スコア116734

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/09/04 08:40 編集

各処理はそのように分割出来るという前提です。
yambejp

2020/09/04 03:31

流れ的にはこんな感じ (async()=>{ await (async()=>{ return Promise.all([ new Promise(resolve=>setTimeout(()=>{console.log("A1");resolve();},300)), new Promise(resolve=>setTimeout(()=>{console.log("A2");resolve();},500)), new Promise(resolve=>setTimeout(()=>{console.log("A3");resolve();},200)), ]); })(); await (async()=>{ return Promise.all([ new Promise(resolve=>setTimeout(()=>{console.log("B1");resolve();},500)), new Promise(resolve=>setTimeout(()=>{console.log("B2");resolve();},200)), new Promise(resolve=>setTimeout(()=>{console.log("B3");resolve();},300)), ]); })(); console.log("C"); })();
退会済みユーザー

退会済みユーザー

2020/09/04 03:46

すみません、前提と質問内容を見返してから回答いただけるとありがたいです。
yambejp

2020/09/04 03:48 編集

逆に上記を理解ください promose.allで非同期の並行処理を実行し、 async/awaitで直列につなげるということです
退会済みユーザー

退会済みユーザー

2020/09/04 03:52

理解しています。これだと変換処理中にデータAを追加することができませんし、そもそも逐次的な処理では無いと思いますがどうなのでしょうか
yambejp

2020/09/04 03:56

ではなにが聞きたいのでしょうか? 非同期ではない処理を非同期に分割する方法ですか?
退会済みユーザー

退会済みユーザー

2020/09/04 04:28 編集

クラス設計についてです
yambejp

2020/09/04 04:08 編集

ごめんなさい、なんか要領を得ないので私は撤退します お役に立てず申し訳ありません がんばってください
退会済みユーザー

退会済みユーザー

2020/09/04 04:15

こちらこそ不明瞭な文章で申し訳ありません
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問