九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
Swift 并行編程現(xiàn)狀和展望 - async/await 和參與者模式

這篇文章不是針對當(dāng)前版本 Swift 3 的,而是對預(yù)計(jì)于 2018 年發(fā)布的 Swift 5 的一些特性的猜想。如果兩年后我還記得這篇文章,可能會(huì)回來更新一波。在此之前,請當(dāng)作一篇對現(xiàn)代語言并行編程特性的不太嚴(yán)謹(jǐn)科普文來看待。

CPU 速度已經(jīng)很多年沒有大的突破了,硬件行業(yè)更多地將重點(diǎn)放在多核心技術(shù)上,而與之對應(yīng),軟件中并行編程的概念也越來越重要。如何利用多核心 CPU,以及擁有密集計(jì)算單元的 GPU,來進(jìn)行快速的處理和計(jì)算,是很多開發(fā)者十分感興趣的事情。在今年年初 Swift 4 的展望中,Swift 項(xiàng)目的負(fù)責(zé)人 Chris Lattern 表示可能并不會(huì)這么快提供語言層級(jí)的并行編程支持,不過最近 Chris 又在 IBM 的一次關(guān)于編譯器的分享中明確提到,有很大可能會(huì)在 Swift 5 中添加語言級(jí)別的并行特性。

這對 Swift 生態(tài)是一個(gè)好消息,也是一個(gè)大消息。不過這其實(shí)并不是什么新鮮的事情,甚至可以說是一門現(xiàn)代語言發(fā)展的必經(jīng)路徑和必備特性。因?yàn)?Objective-C/Swift 現(xiàn)在缺乏這方面的內(nèi)容,所以很多專注于 iOS 的開發(fā)者對并行編程會(huì)很陌生。我在這篇文章里結(jié)合 Swift 現(xiàn)狀簡單介紹了一些這門語言里并行編程可能的使用方式,希望能幫助大家初窺門徑。(雖然我自己也還摸不到門徑在何方…)

Swift 現(xiàn)有的并行模型

Swift 現(xiàn)在沒有語言層面的并行機(jī)制,不過我們確實(shí)有一些基于庫的線程調(diào)度的方案,來進(jìn)行并行操作。

基于閉包的線程調(diào)度

雖然恍如隔世,不過 GCD (Grand Central Dispatch) 確實(shí)是從 iOS 4 才開始走進(jìn)我們的視野的。在 GCD 和 block 被加入之前,我們想要新開一個(gè)線程需要用到 NSThread 或者 NSOperation,然后使用 delegate 的方式來接收回調(diào)。這種書寫方式太過古老,也相當(dāng)麻煩,容易出錯(cuò)。GCD 為我們帶來了一套很簡單的 API,可以讓我們在線程中進(jìn)行調(diào)度。在很長一段時(shí)間里,這套 API 成為了 iOS 中多線程編程的主流方式。Swift 繼承了這套 API,并且在 Swift 3 中將它們重新導(dǎo)入為了更符合 Swift 語法習(xí)慣的形式?,F(xiàn)在我們可以將一個(gè)操作很容易地派發(fā)到后臺(tái)進(jìn)行,首先創(chuàng)建一個(gè)后臺(tái)隊(duì)列,然后調(diào)用 async 并傳入需要執(zhí)行的閉包即可:

let backgroundQueue = DispatchQueue(label: "com.onevcat.concurrency.backgroundQueue")
backgroundQueue.async {
    let result = 1 + 2
}

在 async 的閉包中,我們還可以繼續(xù)進(jìn)行派發(fā),最常見的用法就是開一個(gè)后臺(tái)線程進(jìn)行耗時(shí)操作 (從網(wǎng)絡(luò)獲取數(shù)據(jù),或者 I/O 等),然后在數(shù)據(jù)準(zhǔn)備完成后,回到主線程更新 UI:

let backgroundQueue = DispatchQueue(label: "com.onevcat.concurrency.backgroundQueue")
backgroundQueue.async {
    let url = URL(string: "https://api.onevcat.com/users/onevcat")!
    guard let data = try? Data(contentsOf: url) else { return }

    let user = User(data: data)
    DispatchQueue.main.async {
        self.userView.nameLabel.text = user.name
        // ...
    }
}

當(dāng)然,現(xiàn)在估計(jì)已經(jīng)不會(huì)有人再這么做網(wǎng)絡(luò)請求了。我們可以使用專門的 URLSession 來進(jìn)行訪問。URLSession 和對應(yīng)的 dataTask 會(huì)將網(wǎng)絡(luò)請求派發(fā)到后臺(tái)線程,我們不再需要顯式對其指定。不過更新 UI 的工作還是需要回到主線程:

let url = URL(string: "https://api.onevcat.com/users/onevcat")!
URLSession.shared.dataTask(with: url) { (data, res, err) in
    guard let data = try? Data(contentsOf: url) else {
        return
    }
    let user = User(data: data)
    DispatchQueue.main.async {
        self.userView.nameLabel.text = user.name
        // ...
    }
}.resume()

回調(diào)地獄

基于閉包模型的方式,不論是直接派發(fā)還是通過 URLSession 的封裝進(jìn)行操作,都面臨一個(gè)嚴(yán)重的問題。這個(gè)問題最早在 JavaScript 中臭名昭著,那就是回調(diào)地獄 (callback hell)。

試想一下我們?nèi)绻幸幌盗行枰来芜M(jìn)行的網(wǎng)絡(luò)操作:先進(jìn)行登錄,然后使用返回的 token 獲取用戶信息,接下來通過用戶 ID 獲取好友列表,最后對某個(gè)好友點(diǎn)贊。使用傳統(tǒng)的閉包方式,這段代碼會(huì)是這樣:

LoginRequest(userName: "onevcat", password: "123").send() { token, err in
    if let token = token {
        UserProfileRequest(token: token).send() { user, err in
            if let user = user {
                GetFriendListRequest(user: user).send() { friends, err in
                    if let friends = friends {
                        LikeFriendRequest(target: friends.first).send() { result, err in
                            if let result = result, result {
                                print("Success")
                                self.updateUI()
                            }
                        } else {
                            print("Error: \(err)")
                        }
                    } else {
                        print("Error: \(err)")                    
                    }
                }
            } else {
                print("Error: \(err)")
            }
        }
    } else {
        print("Error: \(err)")
    }
}

這已經(jīng)是使用了尾隨閉包特性簡化后的代碼了,如果使用完整的閉包形式的話,你會(huì)看到一大堆 }) 堆疊起來。else路徑上幾乎不可能確定對應(yīng)關(guān)系,而對于成功的代碼路徑來說,你也需要很多額外的精力來理解這些代碼。一旦這種基于閉包的回調(diào)太多,并嵌套起來,閱讀它們的時(shí)候就好似身陷地獄。

不幸的是,在 Cocoa 框架中我們似乎對此沒太多好辦法。不過我們確實(shí)有很多方法來解決回調(diào)地獄的問題,其中最成功的應(yīng)該是 Promise 或者 Future 的方案。

Promise/Future

在深入 Promise 或 Future 之前,我們先來將上面的回調(diào)做一些整理??梢钥吹剑械恼埱笤诨卣{(diào)時(shí)都包含了兩個(gè)輸入值,一個(gè)是像 token,user 這樣我們接下來會(huì)使用到的結(jié)果,另一個(gè)是代表錯(cuò)誤的 err。我們可以創(chuàng)建一個(gè)泛型類型來代表它們:

enum Result<T> {
    case success(T)
    case failure(Error)
}

重構(gòu) send 方法接收的回調(diào)類型后,上面的 API 調(diào)用就可以變?yōu)椋?/p>

LoginRequest(userName: "onevcat", password: "123").send() { result in
    switch result {
    case .success(let token):
        UserProfileRequest(token: token).send() { result in
            switch result {
            case .success(let user):
               // ...
            case .failure(let error):
                print("Error: \(error)")
            }
        }
    case .failure(let error):
        print("Error: \(error)")
    }
}

看起來并沒有什么改善,對么?我們只不過使用一堆 ({}) 的地獄換成了 switch...case 的地獄。但是,我們?nèi)绻麑?request 包裝一下,情況就會(huì)完全不同。

struct Promise<T> {
    init(resolvers: (_ fulfill: @escaping (T) -> Void, _ reject: @escaping (Error) -> Void) -> Void) {
        //...
        // 存儲(chǔ) fulfill 和 reject。
        // 當(dāng) fulfill 被調(diào)用時(shí)解析為 then;當(dāng) reject 被調(diào)用時(shí)解析為 error。
    }

    // 存儲(chǔ)的 then 方法,調(diào)用者提供的參數(shù)閉包將在 fulfill 時(shí)調(diào)用
    func then<U>(_ body: (T) -> U) -> Promise<U> {
        return Promise<U>{
            //...
        }
    }

    // 調(diào)用者提供該方法,參數(shù)閉包當(dāng) reject 時(shí)調(diào)用
    func `catch`<Error>(_ body: (Error) -> Void) {
        //...
    }
}

extension Request {
    var promise: Promise<Response> {
        return Promise<Response> { fulfill, reject in
            self.send() { result in
                switch result {
                case .success(let r): fulfill(r)
                case .failure(let e): reject(e)
                }
            }
        }
    }
}

我們這里沒有給出 Promise 的具體實(shí)現(xiàn),而只是給出了概念性的說明。Promise 是一個(gè)泛型類型,它的初始化方法接受一個(gè)以 fulfill 和 reject 作為參數(shù)的函數(shù)作為參數(shù) (一開始這可能有點(diǎn)拗口,你可以結(jié)合代碼再讀一次)。這個(gè)類型里還提供了 then 和 catch 方法,then 方法的參數(shù)是另一個(gè)閉包,在 fulfill 被調(diào)用時(shí),我們可以執(zhí)行這個(gè)閉包,并返回新的 Promise (之后會(huì)看到具體的使用例子):而在 reject 被調(diào)用時(shí),通過 catch 方法中斷這個(gè)過程。

在接下來的 Request 的擴(kuò)展中,我們定義了一個(gè)返回 Promise 的計(jì)算屬性,它將初始化一個(gè)內(nèi)容類型為 Response 的 Promise (這里的 Response 是定義在 Request 協(xié)議中的代表該請求對應(yīng)的響應(yīng)的類型,想了解更多相關(guān)的內(nèi)容,可以看看我之前的一篇使用面向協(xié)議編程的文章)。我們在 .success 時(shí)調(diào)用 fulfill,在 .failure 時(shí)調(diào)用 reject。

現(xiàn)在,上面的回調(diào)地獄可以用 then 和 catch 的形式進(jìn)行展平了:

LoginRequest(userName: "onevcat", password: "123").promise
 .then { token in
    return UserProfileRequest(token: token).promise
}.then { user in
    return GetFriendListRequest(user: user).promise
}.then { friends in
    return LikeFriendRequest(target: friends.first).promise
}.then { _ in
    print("Succeed!")
    self.updateUI()
    // 我們這里還需要在 Promise 中添加一個(gè)無返回的 then 的重載
    // 篇幅有限,略過
    // ...
}.catch { error in
    print("Error: \(error)")
}

Promise 本質(zhì)上就是一個(gè)對閉包或者說 Result 類型的封裝,它將未來可能的結(jié)果所對應(yīng)的閉包先存儲(chǔ)起來,然后當(dāng)確實(shí)得到結(jié)果 (比如網(wǎng)絡(luò)請求返回) 的時(shí)候,再執(zhí)行對應(yīng)的閉包。通過使用 then,我們可以避免閉包的重疊嵌套,而是使用調(diào)用鏈的方式將異步操作串接起來。Future 和 Promise 其實(shí)是同樣思想的不同命名,兩者基本指代的是一件事兒。在 Swift 中,有一些封裝得很好的第三方庫,可以讓我們以這樣的方式來書寫代碼,PromiseKit 和 BrightFutures 就是其中的佼佼者,它們確實(shí)能幫助避免回調(diào)地獄的問題,讓嵌套的異步代碼變得整潔。

async/await,“串行”模式的異步編程

雖然 Promise/Future 的方式能解決一部分問題,但是我們看看上面的代碼,依然有不少問題。

  1. 我們用了很多并不直觀的操作,對于每個(gè) request,我們都生成了額外的 Promise,并用 then 串聯(lián)。這些其實(shí)都是模板代碼,應(yīng)該可以被更好地解決。

  2. 各個(gè) then 閉包中的值只在自己固定的作用域中有效,這有時(shí)候很不方便。比如如果我們的 LikeFriend 請求需要同時(shí)發(fā)送當(dāng)前用戶的 token 的話,我們只能在最外層添加臨時(shí)變量來持有這些結(jié)果:

     var myToken: String = ""
     LoginRequest(userName: "onevcat", password: "123").promise
      .then { token in
         myToken = token
         return UserProfileRequest(token: token).promise
     } //...
     .then {
         print("Token is \(myToken)")
         // ...
     }
    
    
  3. Swift 內(nèi)建的 throw 的錯(cuò)誤處理方式并不能很好地和這里的 Result 和 catch { error in ... } 的方式合作。Swift throw 是一種同步的錯(cuò)誤處理方式,如果想要在異步世界中使用這種的話,會(huì)顯得格格不入。語法上有不少理解的困難,代碼也會(huì)迅速變得十分丑陋。

如果從語言層面著手的話,這些問題都是可以被解決的。如果對微軟技術(shù)棧有所關(guān)心的同學(xué)應(yīng)該知道,早在 2012 年 C# 5.0 發(fā)布時(shí),就包含了一個(gè)讓業(yè)界驚為天人的特性,那就是 async 和 await 關(guān)鍵字。這兩個(gè)關(guān)鍵字可以讓我們用類似同步的書寫方式來寫異步代碼,這讓思維模型變得十分簡單。Swift 5 中有望引入類似的語法結(jié)構(gòu),如果我們有 async/await,我們上面的例子將會(huì)變成這樣的形式:

@IBAction func bunttonPressed(_ sender: Any?) {
    // 1
    doSomething()
    print("Button Pressed")
}

// 2
async func doSomething() {
    print("Doing something...")
    do {
        // 3
        let token   = await LoginRequest(userName: "onevcat", password: "123").sendAsync()
        let user    = await UserProfileRequest(token: token).sendAsync()
        let friends = await GetFriendListRequest(user: user).sendAsync()
        let result  = await LikeFriendRequest(target: friends.first).sendAsync()
        print("Finished")

        // 4
        updateUI()
    } catch ... {
        // 5
        //...
    }
}

extension Request {
    // 6
    async func sendAsync() -> Response {
        let dataTask = ...
        let data = await dataTask.resumeAsync()
        return Response.parse(data: data)
    }
}

注意,以上代碼是根據(jù)現(xiàn)在 Swift 語法,對如果存在 async 和 await 時(shí)語言的形式的推測。雖然這不代表今后 Swift 中異步編程模型就是這樣,或者說 async 和 await 就是這樣使用,但是應(yīng)該代表了一個(gè)被其他語言驗(yàn)證過的可行方向。

按照注釋的編號(hào),進(jìn)行一些簡單的說明:

  1. 這就是我們通常的 @IBAction,點(diǎn)擊后執(zhí)行 doSomething。
  2. doSomething 被 async 關(guān)鍵字修飾,表示這是一個(gè)異步方法。async 關(guān)鍵字所做的事情只有一件,那就是允許在這個(gè)方法內(nèi)使用 await 關(guān)鍵字來等待一個(gè)長時(shí)間操作完成。在這個(gè)方法里的語句將被以同步方式執(zhí)行,直到遇到第一個(gè) await??刂婆_(tái)將會(huì)打印 “Doing something…“。
  3. 遇到的第一個(gè) await。此時(shí)這個(gè) doSomething 方法將進(jìn)入等待狀態(tài),該方法將會(huì)“返回”,也即離開棧域。接下來 bunttonPressed 中 doSomething 調(diào)用之后的語句將被執(zhí)行,控制臺(tái)打印 “Button Pressed”。
  4. token,user,friends 和 result 將被依次 await 執(zhí)行,直到獲得最終結(jié)果,并進(jìn)行 updateUI
  5. 理論上 await 關(guān)鍵字在語義上應(yīng)該包含 throws,所以我們需要將它們包裹在 do...catch 中,而且可以使用 Swift 內(nèi)建的異常處理機(jī)制來對請求操作中發(fā)生的錯(cuò)誤進(jìn)行捕獲和處理。換句話說,我們?nèi)绻麑﹀e(cuò)誤不感興趣,也可以使用類似 try? 和 try! 的
  6. 對于 Request,我們需要添加 async 版本的發(fā)送請求的方法。dataTask 的 resumeAsync 方法是在 Foundation 中針對內(nèi)建異步編程所重寫的版本。我們在此等待它的結(jié)果,然后將結(jié)果解析為 model 后返回。

我們上面已經(jīng)說過,可以將 Promise 看作是對 Result 的封裝,而這里我們依然可以類比進(jìn)行理解,將 async 看作是對 Promise 的封裝。對于 sendAsync 方法,我們完全可以將它理解返回 Promise,只不過配合 await,這個(gè) Promise 將直接以同步的方式被解包為結(jié)果。(或者說,await 是這樣一個(gè)關(guān)鍵字,它可以等待 Promise 完成,并獲取它的結(jié)果。)

func sendAsync() throws -> Promise<Response> {
   // ...
}

// await request.sendAsync()
// doABC()

// 等價(jià)于

(try request.sendAsync()).then {
    // doABC()
}

不僅在網(wǎng)絡(luò)請求中可以使用,對于所有的 I/O 操作,Cocoa 應(yīng)當(dāng)也會(huì)提供一套對應(yīng)的異步 API。甚至于對于等待用戶操作和輸入,或者等待某個(gè)動(dòng)畫的結(jié)束,都是可以使用 async/await 的潛在場景。如果你對響應(yīng)式編程有所了解的話,不難發(fā)現(xiàn),其實(shí)響應(yīng)式編程想要解決的就是異步代碼難以維護(hù)的問題,而在使用 async/await 后,部分的異步代碼可以變?yōu)橐酝叫问綍鴮?,這會(huì)讓代碼書寫起來簡單很多。

Swift 的 async 和 await 很可能將會(huì)是基于 Coroutine 進(jìn)行實(shí)現(xiàn)的。不過也有可能和 C# 類似,編譯器通過將 async和 await 的代碼編譯為帶有狀態(tài)機(jī)的片段,并進(jìn)行調(diào)度。Swift 5 的預(yù)計(jì)發(fā)布時(shí)間會(huì)是 2018 年底,所以現(xiàn)在談?wù)撨@些技術(shù)細(xì)節(jié)可能還為時(shí)過早。

參與者 (actor) 模型

講了半天 async 和 await,它們所要解決的是異步編程的問題。而從異步編程到并行編程,我們還需要一步,那就是將多個(gè)異步操作組織起來同時(shí)進(jìn)行。當(dāng)然,我們可以簡單地同時(shí)調(diào)用多個(gè) async 方法來進(jìn)行并行運(yùn)算,或者是使用某些像是 GCD 里 group 之類的特殊語法來將復(fù)數(shù)個(gè) async 打包放在一起進(jìn)行調(diào)用。但是不論何種方式,都會(huì)面臨一個(gè)問題,那就是這套方式使用的是命令式 (imperative) 的語法,而非描述性的 (declarative),這將導(dǎo)致擴(kuò)展起來相對困難。

并行編程相對復(fù)雜,而且與人類天生的思考方式相違背,所以我們希望盡可能讓并行編程的模型保持簡單,同時(shí)避免直接與線程或者調(diào)度這類事務(wù)打交道。基于這些考慮,Swift 很可能會(huì)參考 Erlang 和 AKKA 中已經(jīng)很成功的參與者模型 (actor model) 的方式實(shí)現(xiàn)并行編程,這樣開發(fā)者將可以使用默認(rèn)的分布式方式和描述性的語言來進(jìn)行并行任務(wù)。

所謂參與者,是一種程序上的抽象概念,它被視為并發(fā)運(yùn)算的基本單元。參與者能做的事情就是接收消息,并且基于收到的消息做某種運(yùn)算。這和面向?qū)ο蟮南敕ㄓ邢嗨浦?,一個(gè)對象也接收消息 (或者說,接受方法調(diào)用),并且根據(jù)消息 (被調(diào)用的方法) 作出響應(yīng)。它們之間最大的不同在于,參與者之間永遠(yuǎn)相互隔離,它們不會(huì)共享某塊內(nèi)存。一個(gè)參與者中的狀態(tài)永遠(yuǎn)是私有的,它不能被另一個(gè)參與者改變。

和面向?qū)ο笫澜缰小叭f物皆對象”的思想相同,參與者模式里,所有的東西也都是參與者。單個(gè)的參與者能力十分有限,不過我們可以創(chuàng)建一個(gè)參與者的“管理者”,或者叫做 actor system,它在接收到特定消息時(shí)可以創(chuàng)建新的參與者,并向它們發(fā)送消息。這些新的參與者將實(shí)際負(fù)責(zé)運(yùn)算或者操作,在接到消息后根據(jù)自身的內(nèi)部狀態(tài)進(jìn)行工作。在 Swift 5 中,可能會(huì)用下面的方式來定義一個(gè)參與者:

// 1
struct Message {
    let target: String
}

// 2
actor NetworkRequestHandler {
    var localState: UserID
    async func processRequest(connection: Connection) {
       // ...
       // 在這里你可以 await 一個(gè)耗時(shí)操作
       // 并改變 `localState` 或者向 system 發(fā)消息
    }

    // 3
    message {
        Message(let m): processRequest(connection: Connection(m.target))
    }
}

// 4
let system = ActorSystem(identifier: "MySystem")
let actor = system.actorOf<NetworkRequestHandler>()
actor.tell(Message(target: "https://onevcat.com"))

再次注意,這些代碼只是對 Swift 5 中可能出現(xiàn)的參與者模式的一種猜想。最后的實(shí)現(xiàn)肯定會(huì)和這有所區(qū)別。不過如果 Swift 中要加入?yún)⑴c者,應(yīng)該會(huì)和這里的表述類似。

  1. 這里的 Message 是我們定義的消息類型。
  2. 使用 actor 關(guān)鍵字來定義一個(gè)參與者模型,它其中包含了內(nèi)部狀態(tài)和異步操作,以及一個(gè)隱式的操作隊(duì)列。
  3. 定義了這個(gè) actor 需要接收的消息和需要作出的響應(yīng)。
  4. 創(chuàng)建了一個(gè) actor system (ActorSystem 這里沒有給出實(shí)現(xiàn),可能會(huì)包含在 Swift 標(biāo)準(zhǔn)庫中)。然后創(chuàng)建了一個(gè) NetworkRequestHandler 參與者,并向它發(fā)送一條消息。

這個(gè)參與者封裝了一個(gè)異步方法以及一個(gè)內(nèi)部狀態(tài),另外,因?yàn)樵搮⑴c者會(huì)使用一個(gè)自己的 DispatchQueue 以避免和其他線程共享狀態(tài)。通過 actor system 進(jìn)行創(chuàng)建,并在接收到某個(gè)消息后執(zhí)行異步的運(yùn)算方法,我們就可以很容易地寫出并行處理的代碼,而不必關(guān)心它們的內(nèi)部狀態(tài)和調(diào)度問題了。現(xiàn)在,你可以通過 ActorSystem 來創(chuàng)建很多參與者,然后發(fā)送不同消息給它們,并進(jìn)行各自的操作。并行編程變得前所未有的簡單。

參與者模式相比于傳統(tǒng)的自己調(diào)度有兩個(gè)顯著的優(yōu)點(diǎn):

首先,因?yàn)閰⑴c者之間的通訊是消息發(fā)送,這意味著并行運(yùn)算不必被局限在一個(gè)進(jìn)程里,甚至不必局限在一臺(tái)設(shè)備里。只要保證消息能夠被發(fā)送 (比如使用 IPC 或者 DMA),你就完全可以使用分布式的方式,使用多種設(shè)備 (多臺(tái)電腦,或者多個(gè) GPU) 進(jìn)行并行操作,這帶來的是無限可能的擴(kuò)展性。

另外,由于參與者之間可以發(fā)送消息,那些操作發(fā)生異常的參與者有機(jī)會(huì)通知 system 自己的狀態(tài),而 actor system 也可以根據(jù)這個(gè)狀態(tài)來重置這些出問題的參與者,或者甚至是無視它們并創(chuàng)建新的參與者繼續(xù)任務(wù)。這使得整個(gè)參與者系統(tǒng)擁有“自愈”的能力,在傳統(tǒng)并行編程中想要處理這件事情是非常困難的,而參與者模型的系統(tǒng)得益于此,可以最大限度保障系統(tǒng)的穩(wěn)定性。

這些東西有什么用

兩年下來,Swift 已經(jīng)證明了自己是一門非常優(yōu)秀的 app 語言。即使 Xcode 每日虐我千百遍,但是現(xiàn)在讓我回去寫 Objective-C 的話,我從內(nèi)心是絕對抗拒的。Swift 的野心不僅于此,從 Swift 的開源和進(jìn)化方向,我們很容易看出這門語言希望在服務(wù)器端也有所建樹。而內(nèi)建的異步支持以及參與者模式的并行編程,無疑會(huì)為 Swift 在服務(wù)器端的運(yùn)用添加厚重的砝碼。異步模型對寫 app 也會(huì)有所幫助,更簡化的控制流程以及隱藏起來的線程切換,會(huì)讓我們寫出更加簡明優(yōu)雅的代碼。

C# 的 async/await 曾經(jīng)為開發(fā)者們帶來一股清流,Elixir 或者說 Erlang 可以說是世界上最優(yōu)秀的并行編程語言,JVM 上的 AKKA 也正在支撐著無數(shù)的億級(jí)服務(wù)。我很好奇當(dāng) Swift 遇到這一切的時(shí)候,它們之間的化學(xué)反應(yīng)會(huì)迸發(fā)出怎樣的火花。雖然每天還在 Swift 3 的世界中掙扎,但是我想我的心已經(jīng)飛躍到 Swift 5 的并行世界中去了。

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
JavaScript異步編程
web前端框架Javascript之JavaScript 異步編程史
async/await 是如何讓代碼更加簡潔的?
【全文】狼叔:如何正確的學(xué)習(xí)Node.js
5分種讓你了解javascript異步編程的前世今生,從onclick到await/async
目前最好的 JavaScript 異步方案 async/await
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服