本文仅代表作者观点,欢迎交流
薛定谔的猫
实验描述如下:
把一只猫关在一个封闭的铁容器里面,并且装置以下仪器(注意必须确保这仪器不被容器中的猫直接干扰):在一台盖革计数器内置入极少量放射性物质,在一小时内,这个放射性物质至少有一个原子衰变的概率为50%,它没有任何原子衰变的概率也同样为50%;假若衰变事件发生了,则盖革计数管会放电,通过继电器启动一个榔头,榔头会打破装有氰化氢的烧瓶。经过一小时以后,假若没有发生衰变事件,则猫仍旧存活;否则发生衰变,这套机构被触发,氰化氢挥发,导致猫随即死亡。用以描述整个事件的波函数竟然表达出了活猫与死猫各半纠合在一起的状态。
该实验的核心思想:
1、封闭容器中的猫,50%几率会死亡,50%几率会存活
2、只有打开容器,才能知道猫的状态。也就是说,猫的状态取决于观察者(你)
生活中的薛定谔
讲讲我最近的一个真实经历吧:
最近做了个项目,主要由我来负责。大致需要我做的是:
提供一个接口,该接口功能如下:接受一串入参-->将入参带入模型-->记录入参、时间等参数至数据库-->将模型结果返回。
由于接口功能不算复杂,且给予的时间并不是很多,我选了使用python+flask+sqlalchemy+mysql的项目构架。
顺利地完成开发并部署后,一切貌似都进行得很顺利。
直到有一天,小伙伴跟我说,你这个项目,经常会出现一个现象:
“同样的入参,第一次访问会返回错误,下一次和后面几次就正常返回,过段时间后又会返回错误。”
既然是这样的描述,那我就看看日志记录呗。结果一看:
大致的错误是:MySQL server has gone away
每次接口的访问错误,都是这个。
mysql server has gone away
欧,好吧,看来是sql_alchemy的锅。有问题,那我们就着手解决问题吧。
感谢谷歌大大的帮助。我找到了如下答案和sqlalchemy官方给出的解决方案:
# sqlalchemy 1.2
engine = create_engine("mysql+pymysql://user:pw@host/db", pool_pre_ping=True)
# before sqlalchemy 1.2
from sqlalchemy import exc
from sqlalchemy import event
from sqlalchemy import select
some_engine = create_engine(...)
@event.listens_for(some_engine, "engine_connect")
def ping_connection(connection, branch):
if branch:
# "branch" refers to a sub-connection of a connection,
# we don't want to bother pinging on these.
return
# turn off "close with result". This flag is only used with
# "connectionless" execution, otherwise will be False in any case
save_should_close_with_result = connection.should_close_with_result
connection.should_close_with_result = False
try:
# run a SELECT 1. use a core select() so that
# the SELECT of a scalar value without a table is
# appropriately formatted for the backend
connection.scalar(select([1]))
except exc.DBAPIError as err:
# catch SQLAlchemy's DBAPIError, which is a wrapper
# for the DBAPI's exception. It includes a .connection_invalidated
# attribute which specifies if this connection is a "disconnect"
# condition, which is based on inspection of the original exception
# by the dialect in use.
if err.connection_invalidated:
# run the same SELECT again - the connection will re-validate
# itself and establish a new connection. The disconnect detection
# here also causes the whole connection pool to be invalidated
# so that all stale connections are discarded.
connection.scalar(select([1]))
else:
raise
finally:
# restore "close with result"
connection.should_close_with_result = save_should_close_with_result
使用了官方给出的解决方案(在每次与数据库连接之前,检查一下连接可用性,如果失去了连接,就发送一个'Select 1'命令,重新建立连接)
大家看到这里,肯定都不耐烦了吧😂
读者:作者你在干啥!!废话一大堆,还po代码,是不是为了凑字数啊!!💢💢
读者老爷!我写这么多(有点凑字数嫌疑🤫),肯定是有目的的。不要急哈~
读者:不要糊弄我!😠
修改并部署了以后,确实一切正常了,而且很长一段时间内,没有任何错误返回。但是,虽然一直没有错误,但是,问题来了:你没有办法证明,这个接口一直是好的呀,也许99次访问是好的,谁知道第100次是不是好的,第1000次,第10000次呢......
我的小伙伴笑称:这简直是“薛定谔的正确性”啊。(请允许我杜撰一下这个概念)
对,他说的没错。下一次的返回,一直是两种可能:正确、错误。但是这个结果只有在你发起下一次访问之后才能得知。
薛定谔无处不在
从这次这个项目出发,我得出了一个让人很“绝望”的事实:证明错误(一件事、一个物)的方法千千万,证明正确的方法几乎不存在,因为下一刻的事情,往往是“薛定谔”的,只有在下一刻才能得知。
由此推理:证明一个人是坏人的方法千千万,证明一个人是好人的方法几乎没有!因为是“薛定谔”的。这对于我一个又红又专的青年简直是沉重的打击。我根本无法证明我下一刻是否是好人,因为在这一刻看下一刻的我,50%可能是好人,50%可能是坏人。
那,我怎么让我的小伙伴相信我的修改,确实能做到“不出错”呢?
答案:我在每次检查到“MySQL server has gone away”的时候,在日志中打印一下。
print 'SELECT 1'
这样,1、证明了确实还存在失去连接的情况 2、证明我确实重新连接了 3、接口返回正确
用这样的方法,证明了,我的方法生效了,至少大大提高了我的修改的可靠性!
那么,证明“我自己”是好人的方法,也呼之欲出了:
但行好事,莫问前程
这个引用可能不太恰当,但是这句话就一下子从脑子里蹦出来了,欢迎大家给出批评指导意见!
网友评论