Tech Blog

並行処理と非同期処理

並行処理と並列処理

並行処理(Concurrent Processing)

複数の処理を同時に実行すること。ただしある瞬間には1つの処理だけを実行している。シングルコアCPUで実装可能。擬似的に同時に進んでいるように見える。普通の人の頭は並行処理しかできない。

並列処理(Parallel Processing)

複数の処理を同時に実行すること。ある瞬間に複数の処理を実行している。マルチコアCPUやマルチプロセッサー、GPUなど、ハードウェアのサポートが必要。伝説によれば聖徳太子の頭では並列処理ができたようだ。

同期処理と非同期処理

通常、コンピュータプログラムは休む暇なく次から次へと処理を実行するが、どうしても休まざるを得ないこともある。代表的なのが I/O だ。ユーザーの入力を待つ、ファイルへの書き込みを待つ、ネットワーク経由でデータを取得する、タイマーの設定時間を待つなど、CPU とは桁違いに遅い処理を実行するときに待ちが発生する。

このときにじっと待つのが同期処理(Synchronous Processing)で、一時的に中断して別の処理に実行の機会を譲るのが非同期処理(Asynchronous Processing)である。

協調的なマルチタスキングと非協調的なマルチタスキング

1945年に誕生した ENIAC をはじめとして初期のコンピュータは、電気配線の組み替えでプログラムを表現するにせよ、紙のパンチカードでプログラムを表現するにせよ、一回に一つのプログラムのみロードして実行する機械であった。一つのコンピュータに複数の端末をつなぎ、各端末に少しずつ実行時間を割り当てて高速に切り替えるタイムシェアリングシステムが1960年代始めに実用化されると、人間が考えながらコンピュータへプログラムを入力するような対話型コンピューティングが可能になった。複数のプログラムに実行時間を細切れで与えて処理が並行して進められるマルチタスク機能は、1971年に誕生したUNIXにも受け継がれた。

一つのプログラムが自主的に処理を中断して、他のプログラムに実行機会を譲る方式を協調的なマルチタスキング(Co-operative multitasking)と呼ぶ。一方、強制的に実行中のプログラムを一時停止させて他のプログラムを実行する方式を非協調的なマルチタスキング(Preemptive multitasking)と呼ぶ。タイムシェアリングシステムは preemptive システムの一種であり、UNIXをはじめとする多くの OS のプロセス管理も preemptive である。例外として、たとえば 1990年にリリースされた Windows 3.1 は co-operative multitasking を採用していたため、実行中のプログラムの一つがシステム全体をフリーズさせることがあった。

プロセスとスレッド

現代の OS上で動作するプロセスは preemptive なマルチタスクで動作している。一つのプロセス内でマルチタスクを実現したい場合は、スレッド(Thread)を用いる。OS が各プロセスに割り当てる読み書き可能なメモリには、スタックとヒープの2種類がある。プロセス内でスレッドを立ち上げると、各スレッド毎にスタック領域が割り当てられる。ヒープ領域はスレッド間で共有する。


一つのプロセスに割り当てられるメモリのレイアウト

一つのアプリケーションを一つのプロセス、一つのスレッドで実装するか、一つのプロセス、複数のスレッドで実装するか、複数のプロセスで実装するかは、アプリケーション開発者の任意である。例えば複数のクライアントを同時に相手しなければならないウェブサーバーは、マルチプロセスかつマルチスレッドで動作するのが通例だ。最近のウェブブラウザはタブで複数のサイトを同時に利用できるが、2022年時点の Chrome の場合はデフォルトでサイト毎にプロセスを立ち上げる ようになっている。

ウェブブラウザはシングルスレッド

ウェブブラウザの一つのタブは、<iframe> や Web Worker を用いない限りはシングルスレッドで動作している。画面のレイアウトも画像の表示も JavaScript の実行も、全て一つのメインスレッドで処理する。

そのため、以下のような行儀の悪い JavaScript が含まれていると、そのタブはフリーズする。

<html>
<body>
<script type="text/javascript">
while (true) {}
</script>
<p>test</p>
</body>
</html>

リモートのウェブサーバへリクエストを送るなどの、I/Oにアクセスする関数を呼んだときに、I/Oの処理終了待ちでプログラムが一時的に止まることを「ブロックする」と表現する。I/O操作にはブロッキングAPIとノンブロッキングAPIがある。ブロッキングAPIは同期処理、ノンブロッキングAPIは非同期処理とも呼ばれる。

シングルスレッドである JavaScript は、全てがノンブロッキングAPI、つまり非同期処理で構成されている。例外として alert() 関数や synchronous XHR が挙げられるが、2022年現在、どちらもあまり利用されなくなっている。

AJAX を実現する手段として、1999年に原型が誕生した XHR(XMLHTTPRequest)はよく使われていたが、いま新たに作られるWebアプリケーションは、2015年ころに誕生した後進の fetch API を使うのが普通だろう。

JavaScript の非同期処理

JavaScript で非同期処理を実装する方法はいくつかある。一番最初に使われていたのが callback だった。

setTimeout(() => {
  console.log('called');
}, 1000);

1秒後にコンソールに called と表示するプログラムだ。ちなみに setTimeout は JavaScript の機能ではなく、ブラウザの window オブジェクトが提供する機能である。

これだけならシンプルだが、複数の非同期処理を順番に実行したい場合、Callback地獄(Callback Hell)と呼ばれる見通しの悪いコードになる。

function increment(x, callback) {
  setTimeout(() => {
    callback(x + 1)
  }, 1000)
}

increment(0, (first) => {
  increment(first, (second) => {
    increment(second, (third) => {
      increment(third, (fourth) => {
        console.log(fourth)
      })
    })
  })
})

Callback hell を解消するために JavaScript(ECMAScript 2015)に導入されたのが Promise だ。

const increment = (value) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(value + 1), 1000)
  })
}

increment(0)
  .then((value) => increment(value))
  .then((value) => increment(value))
  .then((value) => increment(value))
  .then((value) => console.log(value))

だいぶ見通しが良くなった。

ちなみに Promise(約束)という言葉は Daniel P. Friedman と David Wise が 1978年に初めて使用しBarbara Liskov と Liuba Shrira がプログラミング言語の要素として持たせることを 1988年に提唱している。Liskov は「リスコフの置換原則(Liskov Substitution Principle)」として、オブジェクト指向言語の根幹をなす概念の提唱者としても名を残している。アメリカの大学でコンピュータサイエンスの博士号を取得した初めての女性でもある。

from Medium
https://medium.com/a-computer-of-ones-own/barbara-liskov-inventor-of-abstract-data-types-9f8908fdcf86

ECMAScript 2017 では、async/await が導入された。これは Promise のシンタックスシュガーであるが、非同期処理を同期処理のように書けるため、さらに見通しが良くなる。

const increment = (value) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(value + 1), 1000)
  })
}

const doIncrements = async () => {
  let value = await increment(0)
  value = await increment(value)
  value = await increment(value)
  value = await increment(value)
  console.log(value)
}

doIncrements()

イベントループ

GUIシステムはUIの描画やユーザーからのマウス、タップのイベントをイベントループで処理している。これはウェブブラウザでも Android でも Windows でも同じで、現存する GUIシステムのほとんどはイベントループ方式を採用している。

擬似コードでイベントループを表現すると、以下のようになる。

event = messageQueue.nextEvent()
while (event != null) {
    process(event)
    event = messageQueue.nextEvent()
}

イベントはメッセージキューに格納され、FIFO (First in, first out) で取り出される。キューにメッセージが無ければ nextEvent() はブロックする。GUIの場合、このループは、必ず一つのスレッドで実行される。画面の描画やユーザーイベントを並行で処理すると前後関係が崩れて意図した結果が得られない。キューにイベントを追加する処理はどのスレッドから実行しても構わないが、キューからイベントを取り出して処理するのは、特定の一つのスレッドに限定する必要がある。

ウェブブラウザはウィンドウ単位でイベントループを持っている。シングルスレッドでこのイベントループを動かし、画面の描画からユーザーイベントの処理まで全てを受け持っているので、重い処理やブロックするような処理を実行すると、ウインドウ全体が停止する。

JavaScript はシングルスレッドであるものの、時間のかかる処理のほぼ全てが非同期APIとして提供されていて、ブラウザが用意した API によりネットワークリクエストを並行実行することも簡単にできるようになっている。当初はシングルスレッドだった JavaScript ではあるが、現在は Web worker によってマルチスレッドを利用することも可能になった。

MacOS、iOS の GUI もメインスレッドでイベントループを実行するという構造になっている。マルチスレッドが利用可能なため、重い処理はスレッドを作成して UIのメインスレッドとは並行して実行させる必要がある。自前でスレッドを作成することも可能ではあるが、多くの場合、2009年の MacOS 10.6、2010年の iOS 4 で利用できるようになった GDC(Grand Central Dispatch)を利用することになる。メインスレッドのメッセージキューとは別に、他のスレッドで処理される複数のメッセージキューが優先度別に用意されているため、開発者自らスレッド管理をすることなく、キューにメッセージを送るだけで並行処理できるようになっている。Apple によると、GCD のキューにメッセージを入れるのは CPU の命令数にしてわずか 15個で実現できる非常に軽い処理である一方で、スレッドを立ち上げるのは数百個の命令を実行する重い処理であるという。素晴らしい軽さと使い勝手を持つ GCD ではあるが、複数の処理を順番に実行したい場合、JavaScript のところで説明した Callback hell のようなネストされたコードになりがちという弱点がある。それを解消するのが、2021年の Swift 5.5 で GCD を置き換えるものとしてサポートされた async/await である。

Android もマルチスレッドであるが、GUI はやはりメインスレッドのイベントループで処理している。Apple の GCD と同様に、メインスレッドのメッセージキューの他、I/Oスレッドで処理される I/O用のメッセージキュー等が用意されている。ネットワーク処理などは I/Oスレッドで実行しないと例外が発生するし、I/Oスレッドで UIの処理を実行しても例外が発生する。

Coroutine

2010年代から、スレッドよりも軽量であるとの触れ込みで Coroutine という並行処理技術が注目され始めた。2009年に登場した Go の Goroutine は Coroutine の一種である。

スレッドが多くの場合 preemptive なのに対して、coroutine は co-operative である。Coroutine は concurrency を提供するが、parallelism は提供しない。Coroutine は関数を一般化したもので、関数の処理を特定の場所で中断(suspend)し、ネットワーク経由でレスポンスを受け取るなど、中断する理由が無くなった後に再開(resume)することができる。

Coroutine は 1958年に Melvin Conway が提唱した用語で、マルチタスクをアセンブラで実装する手段として 1960-1980年代には一般的だった。多くの CPU は、coroutine の実現手段を命令レベルで持っているが、1972年に誕生した C をはじめとする高級言語のほとんどが coroutine を直接サポートしなかったこともあり、2000年代に入り CPUクロック数の高速化が頭打ちになってマルチコア化が進むと、処理のパラレル性を高めるためにスレッドが重用されるようになった。1995年に誕生して2000年前後に大流行した Java が、標準ライブラリとしてスレッドを備えていたのも大きかったと思われる。1993年に誕生した Lua での coroutineサポートなどの例外はあるものの、世の大勢として、coroutine は使われていなかった。

Concurrent programming の手法として Coroutine は一旦忘れ去られたが、2010年代に入り、スレッドよりも軽量な並行処理方法として再び注目されるようになった。

  • 1993年:Lua
  • 2009年:Go (goroutine):元々は co-operative だったが、2020年の Go 1.14 で preemptive になった。
  • 2015年:JavaScript (ECMAScript 2015, ES6 の yield)
  • 2017年:Kotlin coroutine
  • 2021年:Swift 5.5 async / await

インシデント管理ツール PagerDutyの基本的な設定

リンクバルのインフラエンジニアの内藤 @akito_naito です。

前回、PagerDutyを有料版から無料版に切り替えた話をしました。

今回は、PagerDutyの基本的な機能と設定を紹介いたします。紹介するのは以下の機能です。このあたりの設定は、最初に行いましょう!

  • MyProfile – Notification Rules
  • People – On-call Schedules
  • People – Escalation Policies
  • Services – Service Directory

続きを読む

利用サービスの決め方 – インシデント管理ツールのPagerDutyを有料版から無料版に切り替えた話

リンクバルのインフラエンジニアの内藤 @akito_naito です。

インシデント管理ツールは、インシデントがあった際のもろもろを行ってくれるツールです。主な機能は、メールや通知をしたり、担当者のシフトを管理したり、担当者がすぐ確認できない場合は他の担当者にエスカレーションをするなどをしてくれます。

リンクバルではインシデント管理にPgaerdutyのBusinessプランを使っていました。2022年の7月に年払いの契約更新があり、料金が高かったため、他のツールへの移行を検討していました。

他のサービスと検討した結果、PgaerDutyのFreeプランがベストとなり、Businessプランから乗り換えました。

この記事では、どうやってツール・プランを決めていったかを紹介します。参考になれば嬉しいです!

続きを読む

コロナ禍で買って良かったもの 分離キーボード Mistel BAROCCO MD770 の勧め

リンクバルのインフラエンジニアの内藤 @akito_naito です。

リンクバルでは、コロナ禍になった2020年の3月下旬から、全社フルリモート体制になっています。そのおかげもあって、私は宮城に移住して仕事をしています。

で、フルリモートだとずっと座りっぱなしかつひたすらPCに向き合っているので、注意していないと首、肩、腰などが辛くなります。

運動、良いデスクチェアの購入、良い姿勢を頑張るなど対策はいろいろありますが、地味におすすめなのが分離キーボードです!分離キーボードの大きなメリットと、そしてデメリットを紹介します。

先に結論を書いておくと、分量キーボードは非常におすすめです。

続きを読む

マッチングアプリのマッチング数1.8倍に。AIエンジニア、リンクバル賞第1位受賞!

こんにちは!
リンクバル広報担当のでっき~こと出来(デキ)です。

今回はいよいよ、2022年度上半期リンクバル賞第1位に選ばれた、AI推進室の大川さんにインタビュー!現在の業務の内容や業務の中で感じるやりがい、今後の目標などを伺いました。

街コン参加経験ありのシニアAIエンジニア、大川さんってどんな人?

ー入社されてまだ1年経っていない中、今回リンクバル賞第1位を受賞された大川さん。大川さんの入社の決め手ってなんだったんですか?

リンクバルに入る前に街コンに参加したり、マッチングアプリを利用したりしていました。そのため、リンクバルの事業内容にはすごく興味・関心がありました。

そんな中、AI推進室が新設されたということを聞き、経験豊富な室長が着任していることや、組織としてある程度の独立性が担保されている環境で働きやすそうだと思いました。社会人5年目で、AIエンジニアとしてはもちろん、組織づくりに関わるようなことにも少しずつ挑戦していきたいと思い、入社しました。

ーAI推進室では、どんな業務をされているのですか?

AI推進室は、AIエンジンの提供や、デジタルマーケティングのためのデータ整備といった役割を担っています。

その中で私は、AIエンジニアとしてサービスの効率化・改善を目的としたAIエンジンの開発・改善をメインに取り組んでいます。イベントECサイトのmachicon JAPANでいうと、お客様個人個人が興味を持つイベントをレコメンドする。マッチングアプリのCoupLinkでいうと好みの異性をレコメンドするようなAIエンジンをつくっている感じです。


現在は、利用いただいたお客様一人ひとりに合わせた、パーソナライズしたAIを開発・改善していくことに注力しています。昨年末からCoupLinkにおいて独自AIエンジン開発を続け、最大1.8倍マッチング数増加という結果を出すことができました。

▽詳しい内容はこちらから
https://prtimes.jp/main/html/rd/p/000000615.000004786.html

ーマッチング数、1.8倍増加ってすごいですね!そんなバリバリ結果を出されている大川さんのプライベートの部分も伺いたいのですが、最近はどんなことにハマっていますか?

最近ハマっていることは2つあるのですが、1つ目はプロレス観戦です。格闘技がもともと好きなのですが、コロナ禍でプロレス専用の動画配信サービスに登録してから、プロレス観戦をする時間が増えました。特に新日本プロレス所属の選手を応援しています。

やられてもやられても立ち上がって戦うところや、選手それぞれにエピソードがあるところが魅力的です。格闘的な要素だけでなく、エンターテイメントとしても楽しめるので、もっとプロレスについて知る人が増えるといいなと思っています(笑)。

2つ目は、英語の勉強です。イギリス英語の容認発音(Received Pronunciation, RP)がカッコいいなと思いまして(笑)。RPの発音で日本の紹介をしているYou Tubeを観て、日常的な会話を勉強するのがマイブームですね。

もともと英語は苦手なんですが、イギリス英語を習得してイギリス旅行に行って、現地の人と同じ発音で話したいと思っています。

効果が出て少しでも良いサービスになったと実感できると嬉しい!

ー業務をやる中で楽しい・嬉しいと感じるときはどんなときですか?

AIエンジンをリリースした後、効果があったかをABテストで検証していくのですが、そのときにしっかり効果が数字として証明できたときは、すごく嬉しいですね。少しでも良いサービスになったと実感できる瞬間です。

AI推進室では日々チームの仲間と議論や相談をしながら、時に上流から問題を見直しその解決に取り組んでいます。今回の例でも、CoupLinkのレコメンドでは、男女双方の好みを反映しつつレコメンドできるようなAIエンジンを組み立てる必要があり、そこに困難がありました。この問題に私はAIの基本的技術だけでなく離散凸解析という数学を援用することにトライし、結果を残すことができました。その意味で、AI推進室は問題への対処を自分で考えてトライできる土壌があり、とても楽しく仕事をすることができています。


といいながらも、個人的に一番気持ちが高まるときは、自分の読みが完全に当たった瞬間ですね(笑)。事前に計算ベースで、どれぐらい効果が出るかを予測しているのですが、それが当たったときは自分の予測が正しかった~!と自信を持てますね。

ーやりがいを感じるときはどんな時ですか?

もともと課題解決が好きなので、最初分からなかったことが徐々に分かってくるときにやりがいを感じますね。なかなか1回で良いものを作るのは難しいので、段階的に改善して良いものを作り上げていくというのがAIエンジニアの仕事の基本になっていると感じています。

データサイエンティストになる前は数学の研究者をしており、実は数理科学博士の学位を持っています。それもあって数理科学的な方法で答えに迫れたと感じると、モチベーションが上がりますね(笑)。

AI技術に関するこれまでの経験や知見を若い人に伝えたい!

ー大川さんの今後の目標を教えてください!

今AIエンジニアとしてAIの改善・開発に注力しているので、これまで以上に技術と向き合える仕事をしていると感じています。もともと自分の中に、「数理科学の技術を使って社会をよくしたい」という思いがあります。日々の技術研鑽を忘れず、サービス改善や新しいサービスの開発に適用して、どんどん社会を良くしていきたいと思っています。


もう一つ、AI技術の教育にも力を入れていきたいと思っています。今新卒研修をしているのですが、研修資料を一から作って伝えていく中で、人を育てることが好きだなと感じました。

おわりに

「数理科学の技術を使って社会をよくする」という思いで日々の業務に取り組んでいらっしゃる大川さん。何度も検証を繰り返すことで、お客様一人ひとりに合わせた、パーソナライズなサービスへと進化させてくれています。

さらに、AI技術を世の中に広めたいと、若手の育成にも取り組まれており、今後のリンクバルのAIエンジニアがより成長し、活躍できる環境をつくってくれています。ご自身も新しいAIエンジンの開発・改善にどんどんチャレンジし、サービス向上に貢献している姿が、若手にとってはロールモデルになる存在になっているのではないかと感じました。

改めてリンクバル賞受賞おめでとうございます!今後の大川さんのご活躍も楽しみにしています!

 

Advent Calendar 2019 12/22~12/25まとめ

Qiitaが毎年開催している「Qiita Advent Calendar」に、リンクバルのエンジニアも参加しています。

Qiita Advent Calendarとは、クリスマスまでの日数をカウントダウンするアドベントカレンダーの習慣にもとづいて毎年12月1日から25日までの期間限定で展開される記事投稿イベントです。

引用:https://qiita.com/advent-calendar/2019

今年は全日投稿し、Advent Calendar完成しました!エンジニアの皆さん、お疲れさまです!

https://qiita.com/advent-calendar/2019/linkbal

続きを読む

Advent Calendar 2019 12/8~12/14まとめ

Qiitaが毎年開催している「Qiita Advent Calendar」に、リンクバルのエンジニアも参加しています。

Qiita Advent Calendarとは、クリスマスまでの日数をカウントダウンするアドベントカレンダーの習慣にもとづいて毎年12月1日から25日までの期間限定で展開される記事投稿イベントです。

引用:https://qiita.com/advent-calendar/2019

続きを読む

量子コンピューターのプログラミング

2016年に IBM が IBM Q Experience として 5量子ビットの量子コンピュータをクラウド上に無料で開放して数年、Microsoft の Azure Quantum と Amazon の Amazon Bracket が、限定公開ながら相次いで発表されました。量子コンピュータが誰でも使える環境が整いつつあります。

動作原理が現行コンピュータとは根本から異なる上に、現時点ではアセンブラレベルのプログラミング言語しか用意されておらず、しかも実用的なアプリケーションへの適用がまだできないと、3重苦のような環境ですが、20年後は日常的に使われているのではないかと夢想します。

といっても、今の機械学習がアルゴリズムの詳細を理解しなくても使えるように、量子プログラミングもライブラリを呼ぶだけになるのだと思います。論理回路を知らなくてもウェブサイトは作れるし、イーサネットケーブルを流れる信号について知らなくても HTTP で通信できます。

知らなくても使える。でも知らないで使うのは嫌なので、20年後を目指して、量子プログラミングの勉強をすることにしました。
続きを読む

Advent Calendar 2019 12/1~12/7まとめ

Qiitaが毎年開催している「Qiita Advent Calendar」に、リンクバルのエンジニアも参加しています。

Qiita Advent Calendarとは、クリスマスまでの日数をカウントダウンするアドベントカレンダーの習慣にもとづいて毎年12月1日から25日までの期間限定で展開される記事投稿イベントです。

引用:https://qiita.com/advent-calendar/2019

続きを読む

Host a Website on GitHub with Jekyll – Part 2

Hi! I’m Dennis and I’ve been working at Linkbal as a software engineer since October 2017. In Part 1, we took a quick look at Jekyll and how to create and deploy a website to GitHub Pages. In this second and final part, let’s explore some of the customization features Jekyll provides us. 続きを読む