因而,有一些语言经过多返回值来解决这个问题,好比 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一直在使用,略过。