零基础学编程023:用with实现优雅地释放资源

在《零基础学编程022:函数的世界》中我们写了一个函数,通过访问新浪的实时行情服务,得到股票的开盘价。

import urllib.request as req

def price(stock) :
    url = 'http://hq.sinajs.cn/list=' + stock
    with req.urlopen(url) as f :
        hq = f.read().decode('GBK')
        v = hq.split(',')
        return v[1]

新手对 with 的用法不太理解,如果以前学过C#语言,这个with类似于using关键词。先来看看不太好的写法吧:

import urllib.request as req

def price(stock) :
    url = 'http://hq.sinajs.cn/list=' + stock
    f = req.urlopen(url)   # 尽量不要用这种写法!
    hq = f.read().decode('GBK')
    v = hq.split(',')
    f.close() # 当前面发生异常时,不一定能够执行到这条语句
    return v[1]

上面这段代码没有用 with ... as ... 的写法,而是用赋值语句把req.urlopen(url)赋给了 f,在返回开盘价 return v[1] 之前调用了 f.close() 把网络连接关闭。

在绝大多数情况下,这种代码不会有什么问题。但这里的代码访问了网络,而访问网络会有各种异常情况,比如网卡被禁用、WIFI未连接、无法连接互联网、网络地址无效、代理设置不正确、网络服务器故障、防火墙阻挡等等,这些异常都是编程之前无法完全预料的。

我们调用 urlopen() 打开了一个网络连接,在最后务必要保证把它关闭,即调用close() 函数。但当网络已经发生异常了,此时还未执行到close() 函数,程序就已经异常退出了,所以网络连接可能仍处于打开状态。

一般的小程序,这少量的未关闭的网络连接并不会造成什么麻烦,有时操作系统还会在进程关闭时自动释放这些连接,但如果编写服务端程序时,几秒钟之内就可能产生数千个并发连接,当这种问题积累到一定程度后,程序就会出现莫名其妙的错误,而且这种错误特别难定位。

我在2002年用java写过一个网络信息发布系统,当时有人的代码里没有正确地释放Oracle数据库连接,当正式上线时,几分钟之内产生了数百个未释放的数据库连接,Oralce主数据库差点宕掉,幸好我们及时地把程序摘掉,才避免了一次事故的发生。

所以学习编程时,一定要参考别人的例子代码,尤其是参考官方的例子代码。网上流传的一些核心代码只是为了说明具体的用法,写法上并不规范,也没有加入异常处理的相关代码,而真正产品级的代码,会加上许多边界条件检查、异常判断的语句,从而让产品更加健壮。

小结:

  • with 语句用于保证一些资源(文件、网络连接、数据库等)在发生异常时能够正常地关闭或释放
  • 编程初期就养成良好地编程习惯,将错误扼杀在摇篮里
  • with 语句内部会自动调用close()语句释放网络连接,其背后还有比较复杂的实现机制,以后再说

--- END ---

原文发布于微信公众号 - 申龙斌的程序人生(slbGTD)

原文发表时间:2017-02-21

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏张善友的专栏

PostgreSQL 与 MySQL 相比,优势何在?

一、 PostgreSQL 的稳定性极强, Innodb 等引擎在崩溃、断电之类的灾难场景下抗打击能力有了长足进步,然而很多 MySQL 用户都遇到过Serve...

2376
来自专栏文渊之博

时间序列数据库概览

背景 目前对于时序大数据的存储和处理往往采用关系型数据库的方式进行处理,但由于关系型数据库天生的劣势导致其无法进行高效的存储和数据的查询。时序大数据解决方案通...

3116
来自专栏何俊林

刚刚,爱奇艺发布重磅开源项目!

2245
来自专栏大魏分享(微信公众号:david-share)

航空App的订餐系统(上):完整设计一个高级应用-第三篇

版权说明:本文书写过程中参照了红帽的技术文档;本系列文章中的部分测试代码为红帽公司版权所有,因此不能提供源码文件。

822
来自专栏微服务生态

野谈系列之高性能可定制化分布式发号器

刘兵,花名玄靖,开源技术爱好者,高性能Redis中间件NRedis-Proxy作者,目前研究方向为java中间件,微服务等技术。

693
来自专栏Java进阶架构师

dubbo源码解析-详解cluster

今天是小长假的倒数第二天,本来国庆是要加班四天的,后来因为要有事要回家才得以幸免,但是后天上班之后都要搬砖搬到手脱皮是必须的了.但是再忙每周一篇源码解析的承诺都...

691
来自专栏linxu shell指南

软件构件、中间件、面向对象

    1、构件定义:组(构)件是软件系统可替换的、物理的组成部分,它封装了实现体(实现某个职能)并提供了一组接口的实现方法。可以认为组件是一个封装的代码模块或...

884
来自专栏马洪彪

Java设计模式(八)Proxy代理模式

一、场景描述 代理在生活中并不少见,租房子需要找中介,打官司需要找律师,很多事情我们需要找专业人士代理我们做,另一方面,中介和律师也代理了房东、法律程序与我们打...

3366
来自专栏决胜机器学习

设计模式专题(九) ——外观模式

设计模式专题(九) ——外观模式 (原创内容,转载请注明来源,谢谢) 一、概述 外观模式(Facade),为子系统中的一组接口提供一个一致的界面,此模式定义了...

33812
来自专栏猿天地

房价网是怎么使用分布式作业框架elastic-job

Elastic-Job是一个分布式调度解决方案,由两个相互独立的子项目Elastic-Job-Lite和Elastic-Job-Cloud组成。

1062

扫码关注云+社区