2018年2月22日 星期四

異步編程與CPS

有看過"使用Lua Function表示Lambda calculus"的,應該都會對hof(高階函數)不會陌生
使用高階函數 可以做出很多powerful的事請 例如異步編程 所謂異步 舉個栗子就像https://www.zhihu.com/question/19732473所說的

老張愛喝茶,廢話不說,煮開水。
出場人物:老張,水壺兩把(普通水壺,簡稱水壺;會響的水壺,簡稱響水壺)。
1 老張把水壺放到火上,立等水開。(同步阻塞)老張覺得自己有點傻
2 老張把水壺放到火上,去客廳看電視,時不時去廚房看看水開沒有。(同步非阻塞)老張還是覺得自己有點傻,於是變高端了,買了把會響笛的那種水壺。水開之後,能大聲發出嘀~~~~的噪音。
3 老張把響水壺放到火上,立等水開。(異步阻塞)老張覺得這樣傻等意義不大
4 老張把響水壺放到火上,去客廳看電視,水壺響之前不再去看它了,響了再去拿壺。(異步非阻塞)
老張覺得自己聰明了。

這種「不會馬上回傳」的性質,在某些更新頻繁且大量的情況下很有用.就例如ajax,如果一個網站有大量資料且前後相關,一般的逐頁搜索會很沒效率而且很不方便.但如果可以用一些簡單操作逐批資料加載 整個網站就變得人性化多了

至於異步要如何控制呢,這就是我要今天記下的題目:Continuation-passing style(CPS)

所謂CPS 顧名思義就是一種編程的style 在這種style底下 每個動作都會回傳一個函數 這個函數會呼叫下個函數直至動作完結 這個呼叫的函數大多是呼叫他的父函數自身 形成一種連續的時間線 著名的函數式語言Haskell在發明初期都是用CPS處理I/O 以下是一個node.js呼叫sqlite例子

//file:test.js
var sqlite3 = require('sqlite3');
var db = new sqlite3.Database('/tmp/1.db',function() {
  db.run("create table test(name varchar(15))",function(){
    db.run("insert into test values('hello,world')",function(){
      db.all("select * from test",function(err,res){
        if(!err)
          console.log(JSON.stringify(res));
        else
          console.log(err);
      });
    })
  });
});
來源http://blog.csdn.net/chuanqi305/article/details/17930179

node.js用的是GOOGLE的V8引擎,最大特點是對異步的支援,官方聲稱可以「以同步的方式進行異步操作」或許以上的代碼有些人會覺得奇怪用這種方式有什麼好處 先來個負面教材好了
var sqlite3 = require('sqlite3');
var db = new sqlite3.Database('/tmp/1.db',false);
db.run("create table test(name varchar(15))",false);
db.run("insert into test values('hello,world')",false);
db.all("select * from test",function(err,res){
  if(!err)
    console.log(JSON.stringify(res));
  else
    console.log(err);
});
以上的代碼在執行到第4句的時候會拋出一個錯誤 從錯誤訊息裡會看到process找不到一個名為test的table
是為什麼呢 原因是因為 第3句還未執行完成的時候 第4句就會開始執行 所以node找不到table

回想第一個例子 使用這方式的用處是 當sql語句執行完成時 參數裡的callback function才會繼續執行 是不是恍然大悟呢?XD

異步還有很多種實現方式,如lua中的協程(coroutine) ,go中的goroutines(node.js反轉版)有機會再記下來好了

注:以下內容純玩樂性質 對編程毫無用處 認真魔人請戴眼罩觀看
說起高階函數 還有很多很有趣的用法
有一種類似CPS的lambda實例叫y combinator ,和 Self Application Function是一樣的東東
廢話不多說~去圖

有一種類似丘奇數的實例 使用的是lambda的進化版SKI calculus
Ix = x
Kxy = x
Sxyz = xz(yz)
Self-application and recursion:
SIIα = Iα(Iα) = αα
SII(SII) = I(SII)(I(SII)) = I(SII)(SII) = SII(SII)
(S(Kα)(SII))β = Kαβ(SIIβ) = α(SIIβ) = α(ββ)
β = S(Kα)(SII)
SIIβ = ββ = α(ββ) = α(α(ββ)) = ...
The reversal expression:
S(K(SI))Kαβ →
K(SI)α(Kα)β →
SI(Kα)β →
Iβ(Kαβ) →
Iβα →
βα
Boolean logic:
T = K
Kxy = x

F = SK
SKxy = Ky(xy) = y

NOT = (F)(T) = (SK)(K)

(T)NOT = T(F)(T) = F
(F)NOT = F(F)(T) = T

OR = T = K
AND = F = SK
furthermore:https://en.wikipedia.org/wiki/SKI_combinator_calculus

沒有留言:

張貼留言