# -*- encoding: utf-8 -*-
import select
from threading import Thread
from time import time
'''
第37条: 可以用线程来执行阻塞式I/O,但不要用它做平行计算
关键:
1 python实现
CPython运行python过程:
1) 源码->字节码
2)解释器运行字节码
为了保证一致行,采用GIL
2 GIL
含义: 全局解释器锁
本质: 互斥锁
作用: 防止多线程导致字节码解释器的不一致性
缺点: 无法实现多线程,因为同一时刻,只有一条线程可以执行
3 多线程
优点:
1) 多线程使得程序看上去能在同一时间做很多事情
2) 处理阻塞式I/O,借助线程,把程序与耗时的I/O操作分开
例如: 读写文件,网络通信
阻塞式I/O程序样例:
def slowSystemCall():
select.select([], [], [], 0.1)
def runSystemCall():
start = time()
for value in range(10):
slowSystemCall()
end = time()
print "slow system call costs: {value} seconds".format(
value=end - start
)
分析:
主线程会卡在select调用,如果要同时执行塞式I/O操作和计算操作,需要把
系统调用放到其他线程中。
4 总结
GIL全局解释器锁导致python多线程不能平行执行字节码
但是python多线程仍然有用,可以模拟同一时刻执行多个任务,
平行执行多个系统调用,执行阻塞式I/O操作的同时,执行运算操作
参考:
Effectiv Python 编写高质量Python代码的59个有效方法
'''
def factorize(number):
for i in range(1, number + 1):
if number % i == 0:
yield i
def compute():
numbers = [2139079, 1214759, 1516637, 1852285]
start = time()
for number in numbers:
list(factorize(number))
end = time()
print "cost: {value} seconds".format(
value=end - start
)
class FactorizeThread(Thread):
def __init__(self, number):
super(FactorizeThread, self).__init__()
self.number = number
def run(self):
self.factors = list(factorize(self.number))
def threadCompute():
numbers = [2139079, 1214759, 1516637, 1852285]
start = time()
threads = []
for number in numbers:
thread = FactorizeThread(number)
thread.start()
threads.append(thread)
for thread in threads:
thread.join()
end = time()
print "multiple threads cost: {value} seconds".format(
value=end - start
)
def slowSystemCall():
select.select([], [], [], 0.1)
def runSystemCall():
start = time()
for value in range(10):
slowSystemCall()
end = time()
print "slow system call costs: {value} seconds".format(
value=end - start
)
def optimizedRunSystemCall():
start = time()
threads = []
for value in range(10):
thread = Thread(target=slowSystemCall())
thread.start()
threads.append(thread)
for thread in threads:
thread.join()
end = time()
print "optimized system call costs: {value} seconds".format(
value=end - start
)
def computeLocation(index):
pass
def runComputeLocation():
start = time()
threads = []
for value in range(10):
thread = Thread(target=computeLocation(value))
thread.start()
threads.append(thread)
for thread in threads:
thread.join()
end = time()
print "computeLocation costs: {value} seconds".format(
value=end - start
)
def process():
compute()
threadCompute()
runSystemCall()
optimizedRunSystemCall()
runComputeLocation()
if __name__ == "__main__":
process()