python万里长征1(非教)[编码,解码]

第一章 编码、解码

1.0 二进制

不是0 就是1 ,电脑世界就是这么简单。
无(0),名天地之始;有(1),名万物之母。道德经·天地之始

1.1 字符

电脑中的一个字符大都是用一个八位数的二进制数字表示,这样每一字符便可能有256个不同的数值。由于美标只规定了128个编码,剩下的另外128个数码没有规范。
为什么是8位?
答:太极生两仪、两仪生四象、四象生八卦。。。因为问的太八卦了,“规定”不解释,记住就行了,没有为什么!

1.2 编码

编码就是将人类语言(高级语言)编程010这种计算机懂的语言。

下列所有体系不是严格站队的,是时间节点不同,不断的解决了新问题的有兼容之前编码的更完整的方案。哪怕今天的unicode也支持ascii的编码规范,不过ascii只是128个单字节(也就是一个8位二进制组成的字节)规范释义,而unicode是宽字节字符集。也就说unicode代表了超越28=256个释义,毕竟unicode若是双字节也就是可以拥有2(8+8)=65536种释义(码位、我自己称呼包罗万象,简称象)。当然unicode编码不只65536个码位,它的标准里还有平面的概念。

1.2.0 ASCII

上图、不解释

1.2.1 国标

中国人也想想美国人建立一套标准(初始定义在128内,无法让不同计算机通信,虽然后来在128之上定义,但也不够全球通用,程序员估计也就不怎么了解这个过客,但是后来的unicode的快速成熟支持中文肯定还是基于国标的一些规范的,并不能以成败论英雄)称为国标,有纯国标和准国标,详细不说。简称GB。

1.2.2 GBK

GBK码是GB码的扩展字符编码,对多达2万多的简繁汉字进行了编码。

还有几个不常听说,省略。。。

1.2.3 ISO

国际标准组织,这个组织简称ISO,听着就屌屌的。

UCS

通用字符集(Universal Character Set, UCS)是由ISO制定的ISO 10646(或称ISO/IEC 10646)标准所定义的标准字符集。 UCS 是所有其他字符集标准的一个超集。

下面主要UCS字符U+0000到U+007F 与 US-ASCII(ISO 646) 是一致的, U+0000 到 U+00FF 与 ISO8859-1(Latin-1) 也是一致的。
从 U+E000 到 U+F8FF,以及BMP(group 0的平面0被称作Basic Multilingual Plane) 以外的大范围的编码是为私用保留的。
UCS-2用两个字节编码,UCS-4用4个字节编码。

1.2.4 Unicode

位于美国加州的Unicode组织,也叫统一码联盟。
Unicode 组织于约 1982年以 Universal, Unique和Uniform 为主旨也开始开发一个16位字符标准。

目前unicode已经发展到了5.0.0,定义了5个平面的码位对应的字符

彩蛋:易经六十四卦符号都有。。。

问:ucs已经很牛逼了,为啥出现unicode呢?

历史上存在两个独立的尝试创立单一字符集的组织,即国际标准化组织(ISO)和多语言软件制造商组成的统一码联盟。
前者开发的 ISO/IEC 10646 项目,后者开发的统一码项目。因此最初制定了不同的标准。
1991年前后,两个项目的参与者都认识到,世界不需要两个不兼容的字符集。1992年两家组织开始协商,以期折衷寻找共同点,这就是今天的 UCS-2 (BMP,Basic Multilingual Plane,16bit) 和Unicode,但它们仍然是不同的方案,Unicode一般都会采用有关字码最常见的字型,但ISO 10646一般都尽可能采用Century字型

1.3 解码

编码的逆过程。将二进制数据解释成高级语言(解释为人懂的)

第二章 python基础

2.0 数据类型

整数、浮点、布尔值、空值(None类型)、常量、变量

2.1 编码???

计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理。那也就说到了,编码主要是针对字符串来说的。数字编码不编码都是一样的,因为数字在ascii时期就已经定义了全世界通用,都在8位值内,什么编码也不会丢失该数据。
其实编码在第一章已经具体讲过,这里想说的内容在程序中。

ubuntu@ubuntu:~$ python
Python 2.7.12 (default, Dec  4 2017, 14:50:18) 
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> u = u'中文'
>>> s = '中文'
>>> type(u)
<type 'unicode'>
>>> type(s)
<type 'str'>
>>> u.encode('utf-8')
'\xe4\xb8\xad\xe6\x96\x87'
>>> s.encode('utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
>>> s.decode('utf-8')
u'\u4e2d\u6587'
>>> type(u.encode('utf-8'))
<type 'str'>
>>> type(s.decode('utf-8'))
<type 'unicode'>
>>> s == u
__main__:1: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal
False
>>> s.decode('utf-8') == u
True
ubuntu@ubuntu:~$ python3
Python 3.5.2 (default, Nov 23 2017, 16:37:01) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> u = u'中文'
>>> s = '中文'
>>> type(u)
<class 'str'>
>>> type(u)
<class 'str'>
>>> u.encode('utf-8')
b'\xe4\xb8\xad\xe6\x96\x87'
>>> s.encode('utf-8')
b'\xe4\xb8\xad\xe6\x96\x87'
>>> u == s
True

总结来说,python变量存储的都是字节数据(区别在于高8位值是不是丢失了)。

python3变量存储的字符串都是unicode编码规则的字节数据(高8位有意义),而python2只有声明才是,否则存储的默认以ASCII编码的字节数据(高8位也许被覆盖成了别的8位数据,)。

再解码时根本就无法解码成中文,因为没有声明的话,每八位组成的字节都是独立的,丢失了中文(每个中文由两个字符也就是16位)高八位的数据。
bytes字节码型仅表示到8位值代表的字符(美标128种结果),并不包含所有字符。但是str字符串型不只是bytes型。

用Google高级软件工程师Brett Slatkin书(《Effective Python 59 Specific Ways to Write Better Python》编写高质量python代码的59个有效方法)里的话说:

python3有两种表示字符序列的类型:bytes和str。前者包含原始的8位值;后者的实例包含Unicode字符。
python2也有两种表示字符序列的类型,分别叫做str和unicode。与python3不同的是,str的实例包含原始的8位值;而unicode的实例,则包含Unicode字符。

第三章 web开发或websocket开发?

3.0 架构

从运维第一份工作就对架构有个执念。做了两年多运维没有看到任何架构师的希望。
不破不立、离职(工作期间自学python,自己还周末读着职研,想想就想哭,在读研时碰到一个云盘项目时,想web开发了解了django,仅仅了解会搭架构了,运维水平),然后两周不到转型做了python开发,非常感谢领导给的机会。主要负责web开发,不涉及到websocket,当时压根不知道什么是websocket。nginx+uwsgi+django的运维平台就上线了。
那时候都没有应用restful api的理念,完全就是数据的增删改都是手敲的函数、类都不咋写,包括权限管理也是自己写的装饰器,没有应用到restful的以及django的权限管理,傻傻的。同时自学了js、css,调整css,自己写js交互。不到一年时间收获真是满,然而还没算入门(相对培训班出身的真是差很多,毕竟人家上手就是写类,自己看了好多教程偷学,至少知道差哪)。
没怎么涉及到多进程、多线程,也没怎么深入了解异步。异步倒是学会用了celery,然而仅是发邮件做到了异步,不过足以,至少了解了celery和redis,那时redis也不会操作,仅仅是实现了异步发邮件功能达成。

下一个项目、数据展示平台,老架构,后来uwsgi改用了gunicorn,不知道什么区别,公司说用,就试试用了。在http请求里,这个架构还是能抗并发的,然而平台并不是面向公众的,其实马力发挥不出来。
下一个项目,管理系统,学会用了django restframework,写完了数据模型,然后api就出来了,要啥自己写增删改啊,哎,以前傻,但是对于面对对象有了一定理解,前面的自己写的函数都是技术锻炼了,自己手写轮子肯定是不触头了。restframework啥都有,搜索(精确匹配、模糊查询)、分页都含有,分页不是很合适,配合前端的分页器,学会了继承重写,干了三项目才自己领悟到了对象不是那么好谈的,但是谈上了,就水到渠成了,不怕晚。
下一项目,数据展示,涉及多屏幕交互了,然后选用了ws(websocket)定时从redis取数据,数据提交是额外的api,用的依赖包dwebsocket。然后程序开发没问题,架构测试(线上架构nginx+gunicorn+django+dwebsocket+redis+celery,celery集成了定时任务,redis作为消息队列,dws装饰了正常函数作为ws程序,nginx需要配置长链接超时时间,必须比ws推送间隔大)。然后。。。

为啥 websocket 只能出几个数据(几个进程几个api,不能再多)?为啥多进程并发请求没有结果?
两个问题让我开始对多线程、进程、同步、异步又有了飞跃式的理解。

3.1 gunicorn同步、异步

uWSGI 和Gunicorn都是WSGI(Web Server Gateway Interface)容器,uwsgi肯定是支持异步的,需要者请自行查看官方文档。gunicorn也支持,但worker-class默认是sync(同步),若要支持异步,额外安装gevent等(这里不全部列举,只讲我使用的,碰到问题后再去尝试其他异步组件,列举优劣势,先入手一个当太极)就可以。

上面提到过websocket只能有数的api给出数据,就是因为gunicorn默认的同步,一个ws占用一个进程,由于ws是长链接,那就会一直占着,其他的api无法建立链接(区别于http请求,http请求都是短连接,同步情况下很难并发问题的)。而通过异步就可以一个进程跑多个线程级别的ws,而ws推送数据间隔期间都是sleep操作,不会有GIL的弊端(同一个进程一时间只允许一个线程在“运行”),也就解决了ws只出几个数据的问题。

3.2 gunicorn多进程

python虽然有GIL,每个进程只能同时保持一个线程在运行。但是io慢,是不占用线程运行时间的,所以是可以达到IO密集型程序并发的效果的,如果是CPU密集型,那就没有并发效果,平时用time.sleep方法其实是挂起线程的,所以也有并发效果,但是不能掩饰GIL的弊端,毕竟程序都是运行的,然而websocket推送数据俺是用的sleep控制间隔的,不然nginx超时了,ws(websocket简称)也就断掉了。

延伸问题,nginx保持长链接,网页关掉了,ws程序会释放嘛?
答:不会,会驻留,如果ws是循环事件,会一直存在运行直到nginx长链接超时,如果读取数据是直接对redis做pop操作,那其他ws就无法快乐的玩耍了。

python中有个multiprocess库,支持多进程,但是多进程回传数据时,gunicorn拿不到数据,因为gunicorn不支持。我个人理解,gunicorn的异步实现是利用了gevent(python的一个并发框架,以微线程greenlet为核心),然而无法获取多进程的回调结果。

后来老子用django的runserver写了个service 单独去服务那个多进程接口,机制如我。

独立思考:后续会弃用gunicorn和django,无法调用多进程接口,而且在模型设计不多的时候,不那么需要增删改模型操作可以选用tornado。得利于其非阻塞的方式和对epoll的运用,Tornado 每秒可以处理数以千计的连接,因此 Tornado 是实时 Web 服务的一个 理想框架。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值