2017/08/06
 
每次blog.golang.org更新博客,我都迫不及待去读一下;最新的一篇, Contributors Summit,记录了Go贡献者们的一些讨论。我读到一句话,让我感觉得有必要写这个Blog:
 
For instance, it would be nice if io.Reader accepted a context so that blocking read operations could be canceled.(io.Reader接收一个context来取消阻塞的读操作是一个不错的主意)
 
本人瞬间惊呆了,这样一来,io.Reader将会是这样:
type Reader interface { Read(ctx context.Context, p []byte) (n int, err error) }
 
我搜索了一下,发现已经有人向Go2提了这个修改;谢天谢天大多数人并不认可(proposed this change )
 
这篇博客将会讨论所有有关“context”的错误(其实 context还是挺有用的 ),以及Go2需要为它做些什么。
 
Go是一门通用的语言
 
首先我们要明确,Go是一个很好的开发Server程序的语言,但Go并不是专为写Server程序而生。Go是一门通用的语言,就像c,c++,java或python一样。比如我已经使用Go两年了,但却没有写过一个Server程序。
 
因此,我们要以设计一门通用语言的角度来设计Go及其标准库。现在,我想说的是context只适写Server的人,至少大多数情况下如此。
 
Context像病毒一样传染
 
这是context最主要的问题:它会传染!正如这篇博客中所说的(this blog post about the context package
 
At Google, we require that Go programmers pass a Context parameter as the first argument to every function on the call path between incoming and outgoing requests.
(在谷歌,我们要求把context应用到请求从输入到输出所流经的所有函数上面)
 
所有的这些函数都需要传递一个context进去,否则它可能不能被完全Cancel掉。这意味着所有调用的其它库的函数也需要接收context。
 
简而言之,如果你想写一个库,而这个库会被其它的Server程序调用到,那么你就需要在函数中加入context参数!
 
这就是context如何像病毒一样传播。这样有什么坏处呢,我们来看一下:
 
1.Go是一门通用的语言
2.如果一个库会被Server程序调用,它就需要接收context。
3.现在,每个人必须处理context,即使你并不需要它。
 
当然,你可以到处传递context.TODO(),但这简单太糟糕了,它破坏了代码的可读性,让代码看起来丑陋无比,泯灭了我写Go代码的乐趣。
 
如果某天我不得不写出这样的代码:
 
n, err := r.Read(context.TODO(), p)
 
那伙计麻烦给我把枪,让我们Say Goodbye.
 
你也许会辩解:一个库可以为每个函数提供两个版本,一个带context一个不带。额……是的, "database/sql"包就这样做了。尽管它部分解决了这个问题,但看起来很糟糕(不够优雅啊)
 
并且,如果去给学生们教授Go语言,你开始讲解context版的io.Reader接口。学生们问:ctx context.Context是什么东西老师?答案可能会这样:不要管这个,只要传个context.TODO()进来就行了。听起来像 public static void给我的感觉。
 
这里的主要观点是:Context会像病毒一样传播,当我不需要它的话,我不想处理它。
 
“context”包本身的实现并不好。
 
这是一个个人观点。对我来说,context.Context接口有过多的方法。但更主要的问题是:
 
在我的公司里使用ctx.Value,你就会被炒鱿鱼!
 
我不知道是谁想出这个想法让context带上一个无意义的map,(object->object的映射),这有太多问题,我们来列举之:
 
1.很明显的一个,它不是静态类型;
2.它需要记录,哪些Value是哪个函数支持和使用的。我们知道,documentation是永远不会执行的代码。
3.它跟thread-local存储类似。我们知道thread-local存储是多么糟糕的想法。不灵活,使用,测试复杂
4.这不常发生,但是会发生名称冲突。
5.这像一个容易出错的魔法。
 
我知道,ctx.Value会使一些东西实现起来简单。但是我相信,设计API时不使用ctx.Value,你也一定会有替代方案。
 
Context是一个低效的链表。
 
WithCanel,WithDeadline工作需要创建链表。我们需要给WithCancel创建一个goroutine,将cancel信号由前一个context传递到下一个。当然如果context一直没被取消,goroutine就一直存在(相当于resource leak作者认为)
 
最后:
 
ctx context.Context
就像
Foo foo = new Foo();
一样,是Go设计中就极力避免的东西(created to avoid.)。
 
"context"包实际解决了什么问题?
 
即使有这么多的问题,"context"依然是很有用的,因为它解决了Go里面很难处理的一个问题:cancelation(取消)。这是"context"唯一所解决的问题。
 
我们正视现实,Go里面的取消很难实现。在
‘Advanced Go Concurrency Patterns’中有一个很全面和深入的讨论。这个讨论发生在context包引入到Go中之前。因此它讨论的是使用channel来解决cancelation的问题。
 
这个讨论中所提出的解决方案没有可伸缩性,原因如下:
1.cancelation使用的channels不能传递到其它的库或函数,因此只有在内部自己使用。
 
2.想像一个goroutine的树(子gotoutine由父生成),要结束所有的goroutine很容易,只要将cancelation channel关闭即可。但是要结束一个子树却很难。(你需要使用另一个channel,或其它解决方法)
 
"context"解决了这个问题,虽然效率低下且存在很多问题。但这个解决方法却要比已存在的其它办法要好。
 
 
go里我们必须要解决cancelation的问题。当我们使用goroutine时这是必要的。
 
Go2必须正视cancelation的问题!
 
我认为Go提供一个"context"这样的包,本身就是个错误。Go设计的很简单的实现了创建goroutine并在他们之间通信,但是"context"证明Go将goroutine的取消实现的很难用。我认为这个问题需要在语言层面来解决。Go需要在语言层面提供一个解决方案,达到:
 
1.简单,优雅
2.可选 ,非侵入,并非传染
3.健壮,高效
4.只解决cancelation的问题。像Values的功能可以省略了。可以在非常简单的cancelation上实现超时功能。
 
你可能会说:我喜欢context,它不需要改变或使Go语言复杂化,而优雅的解决了这个问题。我不同意。就像所有上面所说的,它不是一个优雅的解决方案,尽管cancellation不是这个语言不可获缺的一部分,但它会变得越来越重要。
 
我想了几种解决方案,但我会在另一篇博客中来写,或者如果有人提出更好的解决方案我会自己保留。这篇博客的目的是指出这个问题。
 
结论:
 
这篇博客试图指出Go语言存在的问题。简而言之,Go语言存在cancelation难的问题,并且"context"包没有很好的解决这个问题。除了语言层面,我没有想出其它解决这个问题的方法。交给Go2来做吧!
 

【翻译】Context should go away for Go 2的更多相关文章

  1. Tomcat翻译--Context Container

    原文:http://tomcat.apache.org/tomcat-7.0-doc/config/context.html#Resource_Definitions The Context Cont ...

  2. 第九篇:在SOUI中使用多语言翻译

    为UI在不同地区显示不同的语言是产品国际化的一个重要要求. 在SOUI中实现了一套类似QT的多语言翻译机制:布局XML不需要调整,程序代码也不需要调整,只需要为不同地区的用户提供不同的语言翻译文件即可 ...

  3. 绝对让你理解Android中的Context

    这个问题是StackOverFlow上面一个热门的问题What is Context in Android? 整理这篇文章的目的是Context确实是一个非常抽象的东西.我们在项目中随手都会用到它,但 ...

  4. 用XPath精确定位节点元素&selenium使用Xpath定位之完整篇

    在利用XSL进行转换的过程中,匹配的概念非常重要.在模板声明语句 xsl:template match = ""和模板应用语句xsl:apply-templates select ...

  5. 【翻译】Android避免内存泄露(Activity的context 与Context.getApplicationContext)

    原谅地址:http://android-developers.blogspot.com/2009/01/avoiding-memory-leaks.html ,英文原文在翻译之后 Android 应用 ...

  6. [翻译].NET Shell Extensions - Shell Context Menus---.net 外壳扩展-右键菜单

    我自己的前言说明: 本文原作者为    Dave Kerr,原文链接为.NET Shell Extensions - Shell Context Menus:,我是在为了完成最新需求的时候查询资料的时 ...

  7. 翻译 | Placing Search in Context The Concept Revisited

    翻译 | Placing Search in Context The Concept Revisited 原文 摘要 [1] Keyword-based search engines are in w ...

  8. 《Django By Example》第四章 中文 翻译 (个人学习,渣翻)

    书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:祝大家新年快乐,这次带来<D ...

  9. [翻译]开发文档:android Bitmap的高效使用

    内容概述 本文内容来自开发文档"Traning > Displaying Bitmaps Efficiently",包括大尺寸Bitmap的高效加载,图片的异步加载和数据缓存 ...

随机推荐

  1. 记一次搭建vsftp服务器坑

    避免踩坑,特此记录... yum -y install vsftpd useradd -d /www -s /sbin/nologin sui # 修改vsftpd配置文件/etc/vsftpd/vs ...

  2. 【转】Entity Framework Extended Library (EF扩展类库,支持批量更新、删除、合并多个查询等)

    E文好的可以直接看https://github.com/loresoft/EntityFramework.Extended 也可以在nuget上直接安装这个包,它的说明有点过时了,最新版本已经改用对I ...

  3. 安天透过北美DDoS事件解读IoT设备安全——Mirai的主要感染对象是linux物联网设备,包括:路由器、网络摄像头、DVR设备,入侵主要通过telnet端口进行流行密码档暴力破解,或默认密码登陆,下载DDoS功能的bot,运行控制物联网设备

    安天透过北美DDoS事件解读IoT设备安全 安天安全研究与应急处理中心(安天CERT)在北京时间10月22日下午启动高等级分析流程,针对美国东海岸DNS服务商Dyn遭遇DDoS攻击事件进行了跟进分析. ...

  4. a标签在编辑器中可以整体删除并且a标签为不可编辑的情况下 标签依然存在(棒棒哒)

    a标签在编辑器中可以整体删除并且a标签为不可编辑的情况下 标签依然存在 因为给a标签的后面 添加了一个空元素,如<i></i>(棒棒哒)<div contentEdita ...

  5. ubuntu默认启动方式修改 psensor命令

    Check UUID sudo blkid Then sudo gedit /etc/default/grub & to pull up the boot loader configurati ...

  6. linux下如何添加一个用户并且让用户获得root权限 备用

    (2010-12-02 09:58:30) 转载▼ 标签: 帐号 权限 杂谈 分类: Linux 测试环境:CentOS 5.5 1.添加用户,首先用adduser命令添加一个普通用户,命令如下: # ...

  7. RTTI,C++类型转换操作符

    body, table{font-family: 微软雅黑; font-size: 10pt} table{border-collapse: collapse; border: solid gray; ...

  8. 十九. Python基础(19)--异常

    十九. Python基础(19)--异常 1 ● 捕获异常 if VS异常处理: if是预防异常出现, 异常处理是处理异常出现 异常处理一般格式: try:     <............. ...

  9. Linux3.10.0块IO子系统流程(4)-- 为请求构造SCSI命令

    首先来看scsi_prep_fn int scsi_prep_fn(struct request_queue *q, struct request *req) { struct scsi_device ...

  10. Interlocked单向链式栈

    线程同步一大部分与原子访问(atomic access)有关, 所谓原子访问, 指的是一个线程在访问某个资源的同时能够保证没有其他线程会在同一时刻访问同一资源. Interlocked单向链式栈的操作 ...