SegmentFault piperck的技术栈最新的文章
2016-09-22T14:56:53+08:00
https://segmentfault.com/feeds/blogs
https://creativecommons.org/licenses/by-nc-nd/4.0/
mysql 编码和汉字存储占用字节问题的探索
https://segmentfault.com/a/1190000006975484
2016-09-22T14:56:53+08:00
2016-09-22T14:56:53+08:00
piperck
https://segmentfault.com/u/piperck
2
<p>MySql 5.5 之前,UTF8 编码只支持1-3个字节,只支持BMP这部分的unicode编码区,BMP是从哪到哪?<br>戳这里 基本就是 0000 ~ FFFF 这一区。</p>
<p>从MySQL 5.5 开始,可支持4个字节UTF编码utf8mb4,一个字符最多能有4字节,所以能支持更多的字符集。</p>
<p>utf8mb4 is a superset of utf8</p>
<p>tf8mb4兼容utf8,且比utf8能表示更多的字符。</p>
<p>至于什么时候用,看你做的什么项目了。。。<br>在做移动应用时,会遇到IOS用户在文本的区域输入emoji表情,如果不做一定处理,就会导致插入数据库异常。</p>
<p>MySql 5.0 以上的版本:</p>
<p>1、一个汉字占多少长度与编码有关:</p>
<p>UTF-8:一个汉字 = 3个字节,英文是一个字节<br>GBK: 一个汉字 = 2个字节,英文是一个字节<br>2、varchar(n) 表示n个字符,无论汉字和英文,MySql都能存入 n 个字符,仅实际字节长度有所区别。</p>
<p>3、MySQL检查长度,可用SQL语言 SELECT LENGTH(fieldname) FROM tablename 这个命令可以看到各行使用的字节数。</p>
<p>mysql版本5.6.32-78.0下面用实际例子来说明问题:</p>
<ol><li><p>首先创建一张临时用表:</p></li></ol>
<pre><code> create TEMPORARY table medivac(
name VARCHAR(10)
); CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
</code></pre>
<ol>
<li>
<p>插入一些数据:</p>
<pre><code>INSERT INTO medivac (name) VALUES ('' at line 1
mysql> INSERT INTO medivac (name) VALUES ('a');
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO medivac (name) VALUES ('哈');
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO medivac (name) VALUES ('\U+1F604');
Query OK, 1 row affected (0.00 sec)
mysql> INSERT INTO medivac (name) VALUES ('哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈');
Query OK, 1 row affected, 1 warning (0.00 sec)</code></pre>
</li>
<li>
<p>查看表中数据:</p>
<pre><code>mysql> select * from medivac
-> ;
+--------------------------------+
| name |
+--------------------------------+
| a |
| 哈 |
| ? |
| 哈哈哈哈哈哈哈哈哈哈 |
+--------------------------------+</code></pre>
</li>
<li>
<p>查看占用字节数:</p>
<pre><code>+--------------+
| length(name) |
+--------------+
| 1 |
| 3 |
| 4 |
| 30 |
+--------------+
</code></pre>
</li>
</ol>
<p>没什么好说的 一目了然,注意,如果存储超过字段规定的最大字符数,后面存储的东西会被无视,并且曝出一个warning。详见过程2的信息。</p>
<p>总结:</p>
<ol>
<li><p>一个varchar存汉字需要使用三个字段在utf8和utf8mb4编码表的情况下。</p></li>
<li><p>如果需要存储emoji表情的需求,新表的默认编码方式应该写为utf8mb4。另外提一点在最新发布的mysql8.0里面,默认编码方式已经是utf8mb4了。</p></li>
<li><p>在utf8和utf8mb4中 varchar(n)这个n是字符,所见即所得,一个a是一个字符一个?也是一个字符 不过就是a这个字符是1个字节 哈这个字符是3个字节 而?这个字符是4个字节表示罢了</p></li>
</ol>
<p>Reference:</p>
<p><a href="https://link.segmentfault.com/?enc=M0ftkVGFBG79AcV%2F4uvKTQ%3D%3D.QiuiRRiiEReSRDq%2Bk0UyJZ6tgq9JfnHnesIk6TCiquduAX1j7%2Fmi01uK8EW44aFfGsRAutsIDpqgkNd5SBIf9w%3D%3D" rel="nofollow">https://www.tutorialspoint.co...</a> MySQL Temporary Tables</p>
<p><a href="https://link.segmentfault.com/?enc=TdBYU3ZrqUsrKjibGT5aKg%3D%3D.IzFxLegyHVJYFkO1IsAQ1UpLp28Gjpgskq%2FfEQeLqyjU0GspReGxpBuE6Of6hKGj" rel="nofollow">https://ruby-china.org/topics...</a> MySQL 数据库 varchar 到底可以存多少个汉字,多少个英文呢?我们来搞搞清楚</p>
python 类和元类(metaclass)的理解和简单运用
https://segmentfault.com/a/1190000006814152
2016-09-04T21:56:14+08:00
2016-09-04T21:56:14+08:00
piperck
https://segmentfault.com/u/piperck
0
<h2>(一) python中的类</h2>
<p>今天看到一篇好文,然后结合自己的情况总结一波。<br>这里讨论的python类,都基于python2.7x以及继承于object的新式类进行讨论。</p>
<p>首先在python中,所有东西都是对象。这句话非常重要要理解元类我要重新来理解一下python中的类。</p>
<pre><code>class Trick(object):
pass
</code></pre>
<p>当python在执行带class语句的时候,会初始化一个类对象放在内存里面。例如这里会初始化一个Trick对象。<br>这个对象(类)自身拥有创建对象(通常我们说的实例,但是在python中还是对象)的能力。</p>
<p>为了方便后续理解,我们可以先尝试一下在新式类中最古老厉害的关键字type。</p>
<pre><code>input:
class Trick(object):
pass
print type('123')
print type(123)
print type(Trick())
output:
<type 'str'>
<type 'int'>
<class '__main__.Trick'>
</code></pre>
<p>可以看到能得到我们平时使用的 str, int, 以及我们初始化的一个实例对象Trick()</p>
<p>但是下面的方法你可能没有见过,type同样可以用来动态创建一个类</p>
<p>type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))</p>
<p>这个怎么用呢,我要用这个方法创建一个类 让我们看下下面的代码</p>
<pre><code>input:
print type('trick', (), {})
output:
<class '__main__.trick'>
同样我们可以实例化这个类对象
input:
print type('trick', (), {})()
output:
<__main__.trick object at 0x109283450>
</code></pre>
<p>可以看到,这里就是一个trick的实例对象了。</p>
<p>同样的这个方法还可以初始化创建类的父类,同时也可以初始化类属性:</p>
<pre><code>input:
class FlyToSky(object):
pass
pw = type('Trick', (FlyToSky, ), {'laugh_at': 'hahahaha'})
print pw().laugh_at
print pw.__dict__
print pw.__bases__
print pw().__class__
print pw().__class__.__class__
output:
hahahaha
{'__module__': '__main__', 'laugh_at': 'hahahaha', '__doc__': None}
(<class '__main__.FlyToSky'>,)
<class '__main__.Trick'>
<type 'type'>
</code></pre>
<p>下面我将依次理一下上面的内容,在此之前我必须先介绍两个魔法方法:</p>
<ol>
<li><p>__class__这个方法用于查看对象属于是哪个生成的,这样理解在python中的所有东西都是对象,类对象也是对象。如果按照以前的思维来想的话就是类是元类的实例,而实例对象是类的实例。</p></li>
<li><p>__bases__这个方法用于得到一个对象的父类是谁,特别注意一下__base__返回单个父类,__bases__以tuple形式返回所有父类。</p></li>
</ol>
<p>好了知道了这两个方法我来依次说一下每行什么意思。</p>
<ol>
<li><p>使用type创建一个类赋值给pw type的接受的三个参数的意思分辨是(类的名称, 类是否有父类(), 类的属性字典{})</p></li>
<li><p>这里初始化一个类的实例,然后尝试去获得父类的laugh_at属性值,然后得到结果hahahaha</p></li>
<li><p>取一个pw的也就是我们常见类的类字典数据</p></li>
<li><p>拿到pw的父类,结果是我们指定的 FlyToSky</p></li>
<li><p>pw的实例pw()属于哪个类初始化的,可以看到是class Trick</p></li>
<li><p>我们再看class trick是谁初始化的? 就是元类type了</p></li>
</ol>
<h2>(二) 什么是元类以及简单运用</h2>
<p>这一切介绍完之后我们总算可以进入正题</p>
<p>到底什么是元类?通俗的就是说,元类就是创建类的类。。。这样听起来是不是超级抽象?<br>来看看这个</p>
<pre><code>Trick = MetaClass()
MyObject = Trick()
</code></pre>
<p>上面我们已经介绍了,搞一个Trick可以直接这样</p>
<pre><code>Trick = type('Trick', (), {})
</code></pre>
<p>可以这样其实就是因为,Type实际上是一个元类,用他可以去创建类。什么是元类刚才说了,元类就是创建类的类。也可以说他就是一个类的创建工厂。</p>
<p>类上面的__metaclass__属性,相信愿意了解元类细节的盆友,都肯定见过这个东西,而且为之好奇。不然我不知道是什么支撑你看到这里的?。使用了__metaclass__这个魔法方法就意味着就会用__metaclass__指定的元类来创建类了。</p>
<pre><code>class Trick(FlyToSky):
pass
</code></pre>
<p>当我们在创建上面的类的时候,python做了如下的操作:<br>Trick中有__metaclass__这个属性吗?如果有,那么Python会在内存中通过__metaclass__创建一个名字为Trick的类对象,也就是Trick这个东西。如果Python没有找到__metaclass__,它会继续在自己的父类FlyToSky中寻找__metaclass__属性,并且尝试以__metaclass__指定的方法创建一个Trick类对象。如果Python在任何一个父类中都找不到__metaclass__,它也不会就此放弃,而是去模块中搜寻是否有__metaclass__的指定。如果还是找不到,好吧那就是使用默认的type来创建Trick。</p>
<p>那么问题来了,我们要在__metaclass__中放置什么呢?答案是可以创建一个类的东西,type,或者任何用到type或子类化type的东西都行。</p>
<h2>(三) 自定义元类</h2>
<p>自定义类的的目的,我总结了一下就是拦截类的创建,然后修改一些特性,然后返回该类。是不是有点熟悉?没错,就是感觉是装饰器干的事情,只是装饰器是修饰一个函数,同样是一个东西进去,然后被额外加了一些东西,最后被返回。</p>
<p>其实除了上面谈到的制定一个__metaclass__并不需要赋值给它的不一定要是正式类,是一个函数也可以。要创建一个使所有模块级别都是用这个元类创建类的话,在模块级别设定__metaclass__就可以了。先写一个来试试看,我还是延用stackoverflow上面那个哥们的例子,将所有的属性都改为大写的。?</p>
<p>来看这个例子:</p>
<pre><code>input:
def upper_attr(class_name, class_parents, class_attr):
"""
返回一个对象,将属性都改为大写的形式
:param class_name: 类的名称
:param class_parents: 类的父类tuple
:param class_attr: 类的参数
:return: 返回类
"""
# 生成了一个generator
attrs = ((name, value) for name, value in class_attr.items() if not name.startswith('__'))
uppercase_attrs = dict((name.upper(), value) for name, value in attrs)
return type(class_name, class_parents, uppercase_attrs)
__metaclass__ = upper_attr
pw = upper_attr('Trick', (), {'bar': 0})
print hasattr(pw, 'bar')
print hasattr(pw, 'BAR')
print pw.BAR
output:
False
True
0
</code></pre>
<p>可以从上面看到,我实现了一个元类(metaclass), 然后指定了模块使用这个元类来创建类,所以当我下面使用type进行类创建的时候,可以发现小写的bar参数被替换成了大写的BAR参数,并且在最后我调用了这个类属性并,打印了它。</p>
<p>上面我们使用了函数做元类传递给类,下面我们使用一个正式类来作为元类传递给__metaclass__</p>
<pre><code>class UpperAttrMetaClass(type):
def __new__(mcs, class_name, class_parents, class_attr):
attrs = ((name, value) for name, value in class_attr.items() if not name.startswith('__'))
uppercase_attrs = dict((name.upper(), value) for name, value in attrs)
return super(UpperAttrMetaClass, mcs).__new__(mcs, class_name, class_parents, uppercase_attrs)
class Trick(object):
__metaclass__ = UpperAttrMetaClass
bar = 12
money = 'unlimited'
print Trick.BAR
print Trick.MONEY
</code></pre>
<p>总结:<br>啊好累好累终于写完了。。。写了好久,总之就像我上面说的,略带一点装饰器的思路去理解元类这件事情,可能会让你豁然开朗。元类这种黑暗魔法按照常理来说是不应该被广泛使用的,从写业务代码一年差不多一年,除了在完成kepler项目的时候稍微黑魔法了一下(实际是根本不需要这样操作),其他地方都没有用到过。等到真正需要的时候,你可能不会去思考为什么要去使用,而是因为要解决问题所以就是要这样写,所以才出现了元类这种东西。我是这样理解的,一个东西存在的真正意义就在于你可以用这个东西去解决以前难以解决的问题,可以让难以解决的问题变得简单起来,而不是为了炫技让一个问题变得复杂起来。</p>
<p>Reference:<br><a href="https://link.segmentfault.com/?enc=uyuHJtXXMyTyFY6xvuOJCQ%3D%3D.oOGXqqEYFfAB6g8WpUmhWlEcvguHWqDiDEKmXFb3iNE%3D" rel="nofollow">http://blog.jobbole.com/21351/</a> 深刻理解Python中的元类<br><a href="https://link.segmentfault.com/?enc=Pbh0cKYSP70sqLWVNV8V3g%3D%3D.nb7O9WJwQJoNpjkmVb8MySb0T7Dg43%2Bcl2P3JmghmVVRzNg7xy29F9VE3gsNybjfTOfQj7eQIEo%2FwmXkVyz3EhKM3SGEyvtE45p7em7Ze%2FI%3D" rel="nofollow">http://stackoverflow.com/ques...</a> What is metaclass in Python</p>
python threading模块使用 以及python多线程操作的实践(使用Queue队列模块)
https://segmentfault.com/a/1190000004413178
2016-02-04T10:48:54+08:00
2016-02-04T10:48:54+08:00
piperck
https://segmentfault.com/u/piperck
3
<h2>介绍</h2>
<p>今天花了近乎一天的时间研究python关于多线程的问题,查看了大量源码 自己也实践了一个生产消费者模型,所以把一天的收获总结一下。</p>
<p>由于GIL(Global Interpreter Lock)锁的关系,纯的python代码处理一般逻辑的确无法活动性能上的极大提升,但是在处理需要等待外部资源返回或多用户的应用程序中,多线程仍然可以作为一个比较好的工具来进行使用。</p>
<h2>threading and thread</h2>
<p>python提供了两个模块thread和threading 来支持python的多线程操作。通俗的讲一般现在我们只使用threading模块来编程了,thread模块定义了很多原始行为,更接近底层,而threading模块抽象了thread模块可用性更好,同时提供更多特性。</p>
<p>现在创建线程的通用方法一般是创建一个类并且继承threading.Thread,然后重写其中的__init__和run()方法。 更多详情可以参考threading模块代码内注释以及代码。下面直接看个例子。</p>
<pre><code>import time
import threading
class Test(threading.Thread):
def __init__(self, name, delay):
super(Test, self).__init__()
self.name = name
self.delay = delay
def run(self):
print "%s delay for %s seconds" % (self.name, self.delay)
time.sleep(self.delay)
c = 0
while True:
print "This is thread %s on line %s" % (self.name, c)
c += 1
if c == 3:
print "End of thread %s" % self.name
break
t1 = Test('Thread1', 5)
t2 = Test('Thread2', 5)
t1.start()
print 'Wait t1 to end'
t1.join()
t2.start()
t2.join()
print 'End of main'</code></pre>
<p>注意一下这一句 :</p>
<pre><code>super(Test, self).__init__()</code></pre>
<p>这是按照模块要求,必须初始化父类的__init__函数 所以使用了super()</p>
<p>其他并没有多少值得注意的地方,</p>
<p>创建线程方便的实例化自己写的继承threading.Thread的类 然后传入对应的参数。</p>
<p>最后使用xxx.start()来运行线程。 使用xxx.join()来阻塞线程。</p>
<p>特别注意的是。继承自Threading类的子类还有一个daemon参数,如果这个参数适用setDaemon()方法置为True之后,主线程将不会等待子线程都结束之后才结束,而是自己运行完之后就结束,这种方式相当粗暴。 如果将daemon参数设置为False的话,主线成将会等待所有子线程结束之后再结束。daemon属性可以通过使用isDaemon()方法获取一个boolean值。</p>
<h2>互斥与同步</h2>
<p>更进一步的,我必须介绍一下线程之间的同步和互斥问题。下面引用《计算机操作系统》中的介绍。</p>
<blockquote>
<p>当线程并发执行时,由于资源共享和线程协作,使用线程之间会存在以下两种制约关系。</p>
<p>(1)间接相互制约。一个系统中的多个线程必然要共享某种系统资源,如共享CPU,共享I/O设备,所谓间接相互制约即源于这种资源共享,打印机就是最好的例子,线程A在使用打印机时,其它线程都要等待。</p>
<p>(2)直接相互制约。这种制约主要是因为线程之间的合作,如有线程A将计算结果提供给线程B作进一步处理,那么线程B在线程A将数据送达之前都将处于阻塞状态。</p>
<p>间接相互制约可以称为互斥,直接相互制约可以称为同步,对于互斥可以这样理解,线程A和线程B互斥访问某个资源则它们之间就会产个顺序问题——要么线程A等待线程B操作完毕,要么线程B等待线程操作完毕,这其实就是线程的同步了。因此同步包括互斥,互斥其实是一种特殊的同步。</p>
<p>在一段时间内只允许一个线程访问的资源就称为临界资源或独占资源,计算机中大多数物理设备,进程中的共享变量等待都是临界资源,它们要求被互斥的访问。每个进程中访问临界资源的代码称为临界区。</p>
</blockquote>
<h2>生产消费者的经典例子</h2>
<p>这里为了介绍这种稍微复杂的概念。 再列出一个生产消费者的例子 使用到了Queue队列。</p>
<pre><code># coding:utf-8
import Queue
import time
import random
import threading
# write_lock = threading.Lock() # 创建primitive锁对象用于控制输出
class Producer(threading.Thread):
# q传递一个队列参数, con传递了一个链接, name传递了一个名字
def __init__(self, q, name):
super(Producer, self).__init__()
self.q = q
# self.con = con
self.name = name
print "Producer " + self.name + "Started"
def run(self):
while True:
# 锁对象常用的acquire获得锁方法和release释放锁方法
# 这里使用的是Thread的Condition对象
# self.con.acquire()
if self.q.full():
print 'Queue is full, producer wait!'
# 手动挂起,并且只能在获得Lock的情况下才可以使用 否则会触发RuntimeError
# 调用wait()会释放Lock 直到该线程被notify(),notifyall()或超时该线程又重新获得Lock
# self.con.wait()
else:
value = random.randint(0, 10)
print self.name + " put " + str(value) + "into queue"
self.q.put((self.name+":"+str(value))) # 放置到队列中
# 通知消费者,notify通知其他线程,被挂起的线程接到通知后会开始运行
# 默认通知一个正在等待该condition的线程,最多唤醒n个线程 必须在获得Lock的情况下使用否则会报错.
# self.con.notify()
# self.con.release() # 释放锁对象
class Consumer(threading.Thread):
def __init__(self, q, name):
super(Consumer, self).__init__()
self.q = q
# self.con = con
self.name = name
print "Consumer " + self.name + "started\n"
def run(self):
while True:
# Condition常用的acquire获得锁方法和release释放锁方法
# self.con.acquire()
if self.q.empty():
print 'queue is empty, consumer wait!'
# self.con.wait()
else:
value = self.q.get() # 从队列中取消息
print self.name + " get " + value + "from queue"
# 发送消息通知生产者
# self.con.notify()
# self.con.release() # 释放锁对象
print 'queue still have ' + str(q.qsize()) + 'task\n'
if __name__ == "__main__":
q = Queue.Queue(10)
# 使用Condition对象可以在某些事件触发或达到特定的条件后才处理数据.
# con = threading.Condition()
# 两个生产者
p1 = Producer(q, "P1")
p2 = Producer(q, "P2")
c1 = Consumer(q, "C1")
p2.start()
p1.start()
c1.start()</code></pre>
<p>若有问题欢迎指出</p>
<h2>参考链接</h2>
<ol>
<li><p>python threading模块文档翻译: <a href="https://link.segmentfault.com/?enc=H%2FjJZ7l9gLfIdadq8A0tfw%3D%3D.lhPKmoOi%2BXE4WNtGxYO%2BrJjuHbB8QqkPXOsi4rDLpl7gK34hi%2FsATAfGXAenb0wPlcmI7UMbxhuaoZ1GQzQ25A%3D%3D" rel="nofollow">http://my.oschina.net/lionets/blog/194577?fromerr=pbWOeveo</a></p></li>
<li><p>多线程7经典线程与互斥总结:<a href="https://link.segmentfault.com/?enc=vCsZhYoDQwEFNF5bqiAaPA%3D%3D.6bGIBZyAYVi2XJRgkTrhJL9hUW37cK7Aii86ldM1ydOt%2FY0SaY7P2GkvNOMnNGQFLPtEEtDv0rMJdZ0leq%2BNiQ%3D%3D" rel="nofollow">http://blog.csdn.net/dazhong159/article/details/7927034</a></p></li>
<li><p>《编写高质量代码改善python程序的91个建议》第48和49建议。</p></li>
</ol>