因而,有一些語言經過多返回值來解決這個問題,好比 Go 語言。Go 語言的不少函數都會返回result, err
兩個值。javascript
Go 語言中的錯誤參數若是要忽略,須要顯式地忽略,用_
這樣的變量來忽略;html
由於返回的 error
是個接口(其中只有一個方法Error()
,返回一個 string
),因此能夠擴展自定義的錯誤處理。java
這樣的處理方式雖然能夠,可是會有潛在的問題。最主要的一個問題就是你不能在中間的代碼中有 return
語句,由於你須要清理資源。在維護這樣的代碼時須要格外當心,由於一不注意就會致使代碼有資源泄漏的問題。python
#define FREE(p) if(p) { \ free(p); \ p = NULL; \ } main() { char *fname=NULL, *lname=NULL, *mname=NULL; fname = ( char* ) calloc ( 20, sizeof(char) ); if ( fname == NULL ){ goto fail; } lname = ( char* ) calloc ( 20, sizeof(char) ); if ( lname == NULL ){ goto fail; } mname = ( char* ) calloc ( 20, sizeof(char) ); if ( mname == NULL ){ goto fail; } ...... fail: FREE(fname); FREE(lname); FREE(mname); ReportError(ERR_NO_MEMORY); }
C++ 的 RAII(Resource Acquisition Is Initialization)機制使用面向對象的特性能夠容易地處理這個事情。RAII 使用 C++ 類的機制,在構造函數中分配資源,在析構函數中釋放資源。git
// 首先,先聲明一個 RAII 類,注意其中的構造函數和析構函數 class LockGuard { public: LockGuard(std::mutex &m):_m(m) { m.lock(); } ~LockGuard() { m. unlock(); } private: std::mutex& _m; } // 而後,咱們來看一下,怎樣使用的 void good() { LockGuard lg(m); // RAII 類:構造時,互斥量請求加鎖 f(); // 若 f() 拋異常,則釋放互斥 if(!everything_ok()) return; // 提前返回,LockGuard 析構時,互斥量被釋放 } // 若 good() 正常返回,則釋放互斥
在 Go 語言中,使用defer
關鍵字也能夠作到這樣的效果:github
func Close(c io.Closer) { err := c.Close() if err != nil { log.Fatal(err) } } func main() { r, err := Open("a") if err != nil { log.Fatalf("error opening 'a'\n") } defer Close(r) // 使用 defer 關鍵字在函數退出時關閉文件。 r, err = Open("b") if err != nil { log.Fatalf("error opening 'b'\n") } defer Close(r) // 使用 defer 關鍵字在函數退出時關閉文件。 }
try - catch - finally
編程模式。算法
try { ... // 正常的業務代碼 } catch (Exception1 e) { ... // 處理異常 Exception1 的代碼 } catch (Exception2 e) { ... // 處理異常 Exception2 的代碼 } finally { ... // 資源清理的代碼 }
這樣的異常處理方式有以下一些好處。編程
int x = add(a, div(b,c));
或 Pizza p = PizzaBuilder().SetSize(sz) .SetPrice(p)...;
但有個致命的問題,那就是在異步運行的世界裏的問題。try 語句塊裏的函數運行在另一個線程中,其中拋出的異常沒法在調用者的這個線程中被捕捉。promise
前面也比較過二者的優缺點,整體而言,彷佛異常捕捉的優點更多一些。應該從場景上來討論這個事纔是正確的姿式。錯誤可分爲三個大類:網絡
資源的錯誤:程序運行環境的問題,代碼去請求一些資源時致使的錯誤,好比打開一個沒有權限的文件,寫文件時出現的寫錯誤,發送文件到網絡端發現網絡故障等錯誤。關鍵性資源不能知足的狀況,內存耗盡、棧溢出、一些程序運行時關鍵性資源不能知足等。
用戶的錯誤:在用戶的API層上出現的問題,好比解析一個XML和JSON文件,或是用戶輸入的字段不合法類的錯誤。
能夠這樣來在邏輯上分類:
在異步編程的世界裏,由於被調用的函數是被放到了另一個線程裏運行,這將致使:
catch
徹底看不到另一個線程中的異常。幾種處理錯誤的方法:
對此,在異步編程的世界裏,咱們也會有好幾種處理錯誤的方法,最經常使用的就是callback
方式。在作異步請求的時候,註冊幾個 OnSuccess()
、OnFailure()
的函數,讓在另外一個線程中運行的異步代碼來回調回來。
function successCallback(result) { console.log("It succeeded with " + result); } function failureCallback(error) { console.log("It failed with " + error); } doSomething(successCallback, failureCallback);
經過註冊錯誤處理的回調函數,讓異步執行的函數在出錯的時候,調用被註冊進來的錯誤處理函數,這樣的方式比較好地解決了程序的錯誤處理。而出錯的語義從返回碼、異常捕捉到了直接耦合錯誤出處函數的樣子。
在 Java 中,在 JDK 1.8 裏也引入了相似 JavaScript 的玩法 —— CompletableFuture
。
鏈式處理:
CompletableFuture.supplyAsync(this::findReceiver) .thenApply(this::sendMsg) .thenAccept(this::notify);
首先,先聲明一個結構體。其中有三個成員:第一個 wg
用於多線程同步;第二個 res
用於存放執行結果;第三個 err
用於存放相關的錯誤。
type Promise struct { wg sync.WaitGroup res string err error }
而後,定義一個初始函數,來初始化 Promise 對象。其中能夠看到,須要把一個函數 f
傳進來,而後調用 wg.Add(1)
對 waitGroup 作加一操做,新開一個 Goroutine 經過異步去執行用戶傳入的函數 f()
,而後記錄這個函數的成功或錯誤,並把 waitGroup 作減一操做。
func NewPromise(f func() (string, error)) *Promise { p := &Promise{} p.wg.Add(1) go func() { p.res, p.err = f() p.wg.Done() }() return p }
而後須要定義 Promise 的 Then 方法。其中須要傳入一個函數,以及一個錯誤處理的函數。而且調用 wg.Wait()
方法來阻塞(由於以前被wg.Add(1)
),一旦上一個方法被調用了 wg.Done()
,這個 Then 方法就會被喚醒。
喚醒的第一件事是,檢查一下以前的方法有沒有錯誤。若是有,那麼就調用錯誤處理函數。若是以前成功了,就把以前的結果以參數的方式傳入到下一個函數中。
func (p *Promise) Then(r func(string), e func(error)) (*Promise){ go func() { p.wg.Wait() if p.err != nil { e(p.err) return } r(p.res) }() return p }
下面,定義一個用於測試的異步方法。這個方面很簡單,就是在數數,而後,有一半的機率會出錯。
func exampleTicker() (string, error) { for i := 0; i < 3; i++ { fmt.Println(i) <-time.Tick(time.Second * 1) } rand.Seed(time.Now().UTC().UnixNano()) r:=rand.Intn(100)%2 fmt.Println(r) if r != 0 { return "hello, world", nil } else { return "", fmt.Errorf("error") } }
下面,來看看實現的 Go 語言 Promise 是怎麼使用的。
func main() { doneChan := make(chan int) var p = NewPromise(exampleTicker) p.Then(func(result string) { fmt.Println(result); doneChan <- 1 }, func(err error) { fmt.Println(err); doneChan <-1 }) <-doneChan }
404
。使用PageNotFound
這樣的標識,這樣人和機器都很容易處理。對於同一個地方不停的報錯,最好不要都打到日誌裏:否則這樣會致使其它日誌被淹沒了,也會致使日誌文件太大。最好的實踐是,打出一個錯誤以及出現的次數。
不要用錯誤處理邏輯來處理業務邏輯:不要使用異常捕捉這樣的方式來處理業務邏輯,而是應該用條件判斷。若是一個邏輯控制能夠用 if - else 清楚地表達,那就不建議使用異常方式處理。異常捕捉是用來處理不指望發生的事情,而錯誤碼則用來處理可能會發生的事。
null
對象的錯誤,要麼都用返回 null,加上條件檢查的模式,要麼都用拋 NullPointerException 的方式處理。不要混用,這樣有助於代碼規範。儘量在錯誤發生的地方處理錯誤:由於這樣會讓調用者變得更簡單。
對於分佈式的系統,推薦使用 APM 相關的軟件:尤爲是使用 Zipkin 這樣的分佈式跟蹤系統來幫助收集時間數據關聯錯誤。
數學的基礎知識。數學真是須要努力學習好的一門功課,尤爲在人工智能火熱的今天。
可是對於系統化學習追求者來講,這篇文章並不具有必定的視野價值。
略
在機器學習(Machine learning)領域,主要有三類不一樣的學習方法: 監督學習(Supervised learning)、 非監督學習(Unsupervised learning)、 半監督學習(Semi-supervised learning), 監督學習:經過已有的一部分輸入數據與輸出數據之間的對應關係,生成一個函數,將輸入映射到合適的輸出,例如分類。 非監督學習:直接對輸入數據集進行建模,例如聚類。 半監督學習:綜合利用有類標的數據和沒有類標的數據,來生成合適的分類函數。
文章中做者描述機器學習主要來講有兩種方法,監督式學習(Supervised Learning)和非監督式學習。
提供一組學習樣本,包括相關的特徵數據以及相應的標籤。程序能夠經過這組樣原本學習相關的規律或是模式,而後經過獲得的規律或模式來判斷沒有被打過標籤的數據是什麼樣的數據。
在監督式學習下,須要有樣本數據或是歷史數據來進行學習,這種方式會有一些問題。好比
對於非監督式學習,也就是說,數據是沒有被標註過的,因此相關的機器學習算法須要找到這些數據中的共性。由於大量的數據是沒有被標識過的,因此這種學習方式可讓大量未標識的數據可以更有價值。
好比,一個在某一年齡段區間的女生購買了某種肥皂,有可能說明這個女生在懷孕期,或是某人購買兒童用品,有可能說明這我的的關係鏈中有孩子,等等。因而這些信息會被用做一些所謂的精準市場營銷活動,從而能夠增長商品銷量。
在監督式的學習的算法下,咱們能夠用一組「狗」的照片來肯定某個照片中的物體是否是狗。而在非監督式的學習算法下,咱們能夠經過一個照片來找到與其類似事物的照片。這兩種學習方式都有各自適用的場景。
機器學習基本就是在已知的樣本數據中尋找數據的規律,在未知的數據中找數據的關係。
機器學習中的基本方法論
機器學習文章:
Machine Learning is Fun!
https://medium.com/@ageitgey/machine-learning-is-fun-80ea3ec3c471
中文翻譯版
https://zhuanlan.zhihu.com/p/24339995
對於監督式學習,有以下經典算法。
對於非監督式的學習,有以下經典算法。
上面的這些相關算法來源自博文《The 10 Algorithms Machine Learning Engineers Need to Know》。
https://www.kdnuggets.com/2016/08/10-algorithms-machine-learning-engineers.html
學習機器學習有幾個課是必需要上的,具體以下。
吳恩達教授(Andrew Ng)在Coursera 上的機器學習課程,網易公開課上也有該課程http://open.163.com/special/opencourse/machinelearning.html
卡內基梅隆大學計算機科學學院湯姆·米切爾(Tom Mitchell)教授的機器學習課程,這裏有英文原版視頻和課件 PDF。《機器學習》
加利福尼亞理工學院亞瑟·阿布·穆斯塔法(Yaser Abu-Mostafa)教授的 Learning from Data 系列課程
除了上述的那些課程外,下面這些資源也很不錯。
YouTube 上的 Google Developers 的 Machine Learning Recipes with Josh Gordon
值得翻閱的圖書。
仿照一下之前在 Outlook 裏設置工做日程的方式,把你的工做安排預先設置到一個能夠共享的日曆上,而後分享給你們,讓你們瞭解你的日程。
我不能說不,可是我要有條件地說是。並且,我要把你給個人壓力再反過來還給你,看似我給了需求方選擇,實際上,我掌握了主動。
「積極主動的態度下對於不合理的事討價還價」。只有學會了說「不」,你纔可以控制好你的時間。
開會,不是討論問題,而是討論方案,開會不是要有議題,而是要有議案。
目前沒有遇到實際場景,略過。
目前沒有遇到實際場景,略過。
本質上來講,並非只有找到了相應的工做咱們才能夠學好一項技術,而是,咱們在經過解決實際問題,在和他人討論,得到高手幫助的環境中,才能更快更有效率地學習和成長。
一項有價值的技術,並不在於這項技術是否有技術含量,而是在於:
軟件天生就是用來完成重複勞動的,天生就是用來作自動化的。
基礎技術老是枯燥和有價值的。數學、算法、網絡、存儲等基礎技術吃得越透,就越容易服務上層的各類衍生技術或產品。
能規模化低成本高效率解決實際問題的技術及其基礎技術,就算是很 low,也是頗有價值的。
### 關於趨勢和將來
這個世界的技術趨勢和將來實際上是被人控制的,因此對於咱們這些在這個世界裏排不上號的人來講,只能默默地跟隨着這些大公司所引領的趨勢和將來。對一些缺錢缺人的創業公司,惟一可以作的,也許只是兩條路,一是用更爲低的成原本提供和大公司相應的技術,另外一條路是在細分垂直市場上作得比大公司更專更精。等着本身有一天長大後,也能加入第一梯隊從而「引領」將來。
Git一直在使用,略過。