Actual (JS, Clojure, python) asynchronous processing

Web Technology   Digital Transformation Technology Artificial Intelligence Technology   Natural Language Processing Technology   Semantic Web Technology   Deep Learning Technology   Online Learning & Reinforcement Learning Technology  Chatbot and Q&A Technology   User Interface Technology   Knowledge Information Processing Technology   Reasoning Technology  Clojure Programming

In the previous article, I gave an overview of parallel / parallel and asynchronous processing. This time we will actually check in several languages.

First of all, about the javascript case @ kiyodori’s. There was a good example in “What does asynchronous processing mean? Learn from scratch with JavaScript”, so I will post it. First, prepare javascript for normal operation and the following files as sync_sleep.js.

console.log("start");

function sleep(milliSeconds) {
  var startTime = new Date().getTime();
  while (new Date().getTime() < startTime + milliSeconds);

  console.log("sleepが完了しました。");
}

sleep(5000); // 実行するのに5秒かかる

console.log("end");

When the above file is executed using node, it becomes as follows.

$ node sync_sleep.js
start
sleepが完了しました。
end

On the other hand, prepare the following file as number.txt

1
2

Create the following javascript file and execute it on Node.

console.log("start");

var fs = require('fs');
fs.readFile("number.txt", "utf-8", function(err, data){
  if (err) throw err;
  console.log("

The execution result is as follows.

$ node async_readfile.js
start
end
ファイルの読み取り準備ができました。
1
2

Unlike the previous one, the reading of the file described earlier in the code is executed after the end display described in the later code. The file read function fs.readFile is predefined as an asynchronous function, and when it is called, it stops once and executes the latter part, resulting in the above output. In this way, javascript was born as a language related to IO that works in a web browser, so many functions that “work like that” are implemented from the beginning.

Other than the default functions as described above, we will use callback functions that have appeared many times before. A sample is shown below.

function sleep(callback) {
  setTimeout(function() {
    callback(null, '現在時刻:' + new Date());
  }, 1000);
}

sleep(function(err, res) {
  console.log(res);
  sleep(function(err, res) {
    console.log(res);
    sleep(function(err, res) {
      console.log(res);
    });
  });
});

If a multi-stage asynchronous process is actually executed by using a callback function as an argument in this way, it becomes a complicated process called callback hell.

On the other hand, in other languages, libraries corresponding to “asynchronous processing” having each characteristic are prepared, and they are used in combination with ordinary functions.

Clojure, for example, does this with a library called core.async. This takes the form of creating a go-block with a go macro that uses the Go-lang concept, which is good at parallel processing, and realizing asynchronous operation only within that block. In addition, a channel is used as data for exchanging data between blocks.

The go macro creates a state machine that makes one revolution each time there is an input to a channel. At the time of this one rotation, a thread is assigned to the go block that was waiting for the channel, the processing runs using the CPU until the next channel input / output, and the processing is reflected in another go block at the channel input / output. It works efficiently on a limited CPU without spawning a ton of threads.

Here is a code example in Clojure.

(import '[java.util Date])
(require '[clojure.core.async :refer [chan go-loop >! <! timeout] :as async])
(def ch (chan)) ; チャネルを作る

;; 書き込み非同期ブロック
(go-loop []
 (when (>! ch (Date.)) ; チャネルに書く
   (<! (timeout 2000)) ; 2秒待つ
   (recur)))

;; 読み込み非同期ブロック
(go-loop []
 (when-let [date (<! ch)] ; チャネルを読む
   (println "now:" date)
   (recur)))  

The code is very simple: define the channel, define each block to write and read to the channel, and each block keeps looping until the channel is closed. Since it is a structure that you can write as many blocks as you need and arrange them side by side, you will not fall into the callback hell with Javascript as described above.

For comparison, the code for asynchronous processing in python is shown.

mport asyncio

Seconds = [
    ("first", 5),
    ("second", 0),
    ("third", 3)
]

async def sleeping(order, seconds, hook=None):
    await asyncio.sleep(seconds)
    if hook:
        hook(order)
    return order

async def basic_async():
    # the order of result is nonsequential (not depends on order, even sleeping time)
    for s in Seconds:
        r = await sleeping(*s
        print("{0} is finished.".format(r))
    return True

if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    loop.run_until_complete(basic_async())

Use asyncio as a library, specify heavy processing in the await part in the event loop generated by loop = asyncio.get_event_loop (), and start “other processing in the event loop” when it reaches there. Is a feature.

コメント

タイトルとURLをコピーしました