本文目录一览:
python GIL 和 线程锁是不是同一个东西
今天看到一篇文章,讲述的是几个提升python性能的项目:传送门
在看的过程中,接触到一个名词,一个从学python开始就一直看到,但是从来都是一知半解的名词,心里不开心,必须把它搞明白,对了,这个词就是 GIL。网上搜索了一些资料,粗浅的理解了什么是GIL,自己感觉学习的过程比较好,感觉略有收获,老规矩,为了巩固知识,自己整片文章出来写一写,其实好多文章已经写的很完善了,所以这篇随笔,只做知识巩固,如有雷同,请各位原创作者原谅,小菜鸟一枚,如果哪里写的有问题,还请各位前辈不吝指正。
一句话:解决多线程之间数据完整性和状态同步的最简单方法自然就是加锁。
首先,GIL的全名,Global Interpreter Lock,鉴于英文水平,不做名词翻译,以免误导。大体解释一下,这个锁就是用来为了解决Cpython多线程中线程不安全问题引入的一个全局排它锁,它的作用就是在多线程情况下,保护共享资源,为了不让多个线程同时操作共享资源,导致不可预期的结果而加上的锁,在一个线程操作共享资源时,其他线程请求该资源,只能等待GIL解锁。这个设置在Cpython刚引入多线程概念的时候就有了,然后后续的各种包和组件开发都不可避免的受到了GIL的影响,所以有人会说,python在多线程处理的时候很慢。python GIL实现方式类似于如下伪代码:
if __name__ == '__main__':
GIL锁开始运作
主线程做操作
主线程完成操作
GIL锁释放资源
所以多线程共同操作共享资源的时候,有一个线程竞得了资源,它就被GIL锁保护起来,其他线程只能是在那里等着,但是这个时候,线程的休眠唤醒,全部会消耗CPU资源,所以嘞,就会慢。
看到这个时候,我又发现了一个名词:线程安全。这个名词,也是那种特别熟悉,但就是无法清晰的说出它是啥的概念。查了资料,在这记一下:
线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。 线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。
我自己想了一下,大约就是这样,比如整个列表,俩个线程同时在列表中append操作,如果没有锁的保护,在机缘巧合之下,俩个线程同时先后申请了空间且没来得及插入数据,然后这时列表中只会有一个空间,那么在插入过程中只能有一个数据写入,会造成不可知后果,有可能报错终止,有可能有一个线程操作没成功,那么这个就是线程不安全了,大白话说,只要线程之间没有共享资源,那么就是线程安全的,有共享资源,为了保证线程安全,需要引进锁的机制。
而后的文章中,有前辈做过实验:
顺序执行的单线程(single_thread.py)#! /usr/bin/pythonfrom threading import Threadimport timedef my_counter():
i = 0 for _ in range(100000000):
i = i + 1 return Truedef main():
thread_array = {}
start_time = time.time() for tid in range(2):
t = Thread(target=my_counter)
t.start()
t.join()
end_time = time.time() print("Total time: {}".format(end_time - start_time))if __name__ == '__main__':
main()
同时执行的两个并发线程(multi_thread.py)#! /usr/bin/pythonfrom threading import Threadimport timedef my_counter():
i = 0 for _ in range(100000000):
i = i + 1 return Truedef main():
thread_array = {}
start_time = time.time() for tid in range(2):
t = Thread(target=my_counter)
t.start()
thread_array[tid] = t for i in range(2):
thread_array[i].join()
end_time = time.time() print("Total time: {}".format(end_time - start_time))if __name__ == '__main__':
main()
最终结果如下:
过程证明了因为GIL的存在,导致python在使用多线程的时候反而不如顺序执行快。
此处我又温习了一下python线程:
线程的顺序执行还是多线程并发,取决于join函数的位置。join函数的作用是等待当前线程结束,所以每一个线程创建之后,调用start函数,这是在后面跟上该线程的join函数,那么就是顺序执行,如果多个线程先完成创建和start,最后加上join函数,那么就变成了多线程并发。
这就是今天的学习内容,其实所有知识网上都能找到,更想分享的是一种学习的方法,一种本身很不推荐的学习方法,那就是类似于探索性测试的学习,啥不懂就去看啥,有些时候,我们学习东西确实不能非要究其内在,软件行业的学习本身在非本行人事看来就特别神奇且枯燥,所以最初的学习,我们需要整个图形界面,让我们学到的东西有了成就感,如果上来先去研究机器码,那么没几个人愿意学下去,但是不管怎样,既然走上了软件行业的道路,这种探索性,打破砂锅问到底的学习,在我的感觉里应该是必经之路,也就是所谓的底层研究。以安卓开发举例,如果做安卓开发的,虽然能写出很漂亮的界面,解决所有的bug,如果不了解安卓系统linux层的知识,在我的眼里,从未把这种研发看做大牛。当然我并不觉得不了解linux底层的安卓研发可以解决任何bug
当下的软件行业进入了一个神奇的阶段,我已经听过无数遍的理论,培训机构出来就能赚钱,大学读着没用,在这里不讨论教育体制问题,从个人情感上,我觉得大学教育虽然没有教给学生直接找工作的技能,但是给了所有学生一个能够了解基础知识的园地,换而言之,作为行业的一员,总应该有将行业发展起来的觉悟,行业内整体风气,缺乏静下心来的沉淀。在大谈敏捷,行为驱动,机器学习的同时,自己需要静下心来回头看看,基础已然不牢,再走下去是否有些危险。是不是学习软件技术,就是为了获取互联网行业那虚高的工资,是否已经局限于第三方框架,一旦框架出现问题,只能打给客服而束手无策,是否有过没有做任何尝试就将bug归咎于安卓系统,阿里中间件等等,是不是旧技术还没用明白,为了新技术就可以不再去研究。
还是小菜鸟,在此大谈行业发展难免有些放肆,如有不对的地方,还请各位前辈不吝指正
怎么用python写tensorflow
开始使用
TensorFlow并不是一个纯粹的神经网络框架, 而是使用数据流图进行数值分析的框架.
TensorFlow使用有向图(graph)表示一个计算任务.图的节点称为ops(operations)表示对数据的处理,图的边flow 描述数据的流向.
该框架计算过程就是处理tensor组成的流. 这也是TensorFlow名称的来源.
TensorFlow使用tensor表示数据. tensor意为张量即高维数组,在python中使用numpy.ndarray表示.
TensorFlow使用Session执行图, 使用Variable维护状态.tf.constant是只能输出的ops, 常用作数据源.
下面我们构建一个只有两个constant做输入, 然后进行矩阵乘的简单图:
from tensorflow import Session, device, constant, matmul'''构建一个只有两个constant做输入, 然后进行矩阵乘的简单图:'''#如果不使用with session()语句, 需要手动执行session.close().
#with device设备指定了执行计算的设备:
# "/cpu:0": 机器的 CPU.
# "/gpu:0": 机器的第一个 GPU, 如果有的话.
# "/gpu:1": 机器的第二个 GPU, 以此类推.
with Session() as session: # 创建执行图的上下文
with device('/cpu:0'): # 指定运算设备
mat1 = constant([[3, 3]]) # 创建源节点
mat2 = constant([[2], [2]])
product = matmul(mat1, mat2) # 指定节点的前置节点, 创建图
result = session.run(product) # 执行计算 print(result)123456789101112131415161718
下面使用Variable做一个计数器:
from tensorflow import Session, constant, Variable, add, assign, initialize_all_variables
state = Variable(0, name='counter') # 创建计数器one = constant(1) # 创建数据源: 1val = add(state, one) # 创建新值节点update = assign(state, val) # 更新计数器setup = initialize_all_variables() # 初始化Variablewith Session() as session:
session.run(setup) # 执行初始化
print(session.run(state)) # 输出初值
for i in range(3):
session.run(update) # 执行更新
print(session.run(state)) # 输出计数器值12345678910111213
在使用变量前必须运行initialize_all_variables()返回的图, 运行Variable节点将返回变量的值.
本示例中将构建图的过程写在了上下文之外, 而且没有指定运行设备.
上面示例中session.run只接受一个op作为参数, 实际上run可以接受op列表作为输入:
session.run([op1, op2])1
上述示例一直使用constant作为数据源, feed可以在运行时动态地输入数据:
from tensorflow import Session, placeholder, mul, float32
input1 = placeholder(float32)
input2 = placeholder(float32)
output = mul(input1, input2)with Session() as session: print session.run(output, feed_dict={input1: [3], input2: [2]})1234567
实现一个简单神经网络
神经网络是应用广泛的机器学习模型, 关于神经网络的原理可以参见这篇随笔, 或者在tensorflow playground上体验一下在线demo.
首先定义一个BPNeuralNetwork类:
class BPNeuralNetwork:
def __init__(self):
self.session = tf.Session()
self.input_layer = None
self.label_layer = None
self.loss = None
self.trainer = None
self.layers = [] def __del__(self):
self.session.close()1234567891011
编写一个生成单层神经网络函数,每层神经元用一个数据流图表示.使用一个Variable矩阵表示与前置神经元的连接权重, 另一个Variable向量表示偏置值, 并为该层设置一个激励函数.
def make_layer(inputs, in_size, out_size, activate=None):
weights = tf.Variable(tf.random_normal([in_size, out_size]))
basis = tf.Variable(tf.zeros([1, out_size]) + 0.1)
result = tf.matmul(inputs, weights) + basis if activate is None: return result else: return activate(result)12345678
使用placeholder作为输入层.
self.input_layer = tf.placeholder(tf.float32, [None, 2])1
placeholder的第二个参数为张量的形状, [None, 1]表示行数不限, 列数为1的二维数组, 含义与numpy.array.shape相同.这里, self.input_layer被定义为接受二维输入的输入层.
同样使用placeholder表示训练数据的标签:
self.label_layer = tf.placeholder(tf.float32, [None, 1])1
使用make_layer为神经网络定义两个隐含层, 并用最后一层作为输出层:
self.loss = tf.reduce_mean(tf.reduce_sum(tf.square((self.label_layer - self.layers[1])), reduction_indices=[1]))1
tf.train提供了一些优化器, 可以用来训练神经网络.以损失函数最小化为目标:
self.trainer = tf.train.GradientDescentOptimizer(learn_rate).minimize(self.loss)1
使用Session运行神经网络模型:
initer = tf.initialize_all_variables()# do trainingself.session.run(initer)
for i in range(limit):
self.session.run(self.trainer, feed_dict={self.input_layer: cases, self.label_layer: labels})12345
使用训练好的模型进行预测:
self.session.run(self.layers[-1], feed_dict={self.input_layer: case})1
完整代码:
import tensorflow as tfimport numpy as npdef make_layer(inputs, in_size, out_size, activate=None):
weights = tf.Variable(tf.random_normal([in_size, out_size]))
basis = tf.Variable(tf.zeros([1, out_size]) + 0.1)
result = tf.matmul(inputs, weights) + basis if activate is None: return result else: return activate(result)class BPNeuralNetwork:
def __init__(self):
self.session = tf.Session()
self.input_layer = None
self.label_layer = None
self.loss = None
self.optimizer = None
self.layers = [] def __del__(self):
self.session.close() def train(self, cases, labels, limit=100, learn_rate=0.05):
# 构建网络
self.input_layer = tf.placeholder(tf.float32, [None, 2])
self.label_layer = tf.placeholder(tf.float32, [None, 1])
self.layers.append(make_layer(self.input_layer, 2, 10, activate=tf.nn.relu))
self.layers.append(make_layer(self.layers[0], 10, 2, activate=None))
self.loss = tf.reduce_mean(tf.reduce_sum(tf.square((self.label_layer - self.layers[1])), reduction_indices=[1]))
self.optimizer = tf.train.GradientDescentOptimizer(learn_rate).minimize(self.loss)
initer = tf.initialize_all_variables() # 做训练
self.session.run(initer) for i in range(limit):
self.session.run(self.optimizer, feed_dict={self.input_layer: cases, self.label_layer: labels}) def predict(self, case):
return self.session.run(self.layers[-1], feed_dict={self.input_layer: case}) def test(self):
x_data = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y_data = np.array([[0, 1, 1, 0]]).transpose()
test_data = np.array([[0, 1]])
self.train(x_data, y_data)
print(self.predict(test_data))
nn = BPNeuralNetwork()
nn.test()12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
上述模型虽然简单但是使用不灵活, 作者采用同样的思想实现了一个可以自定义输入输出维数以及多层隐含神经元的网络, 可以参见dynamic_bpnn.py
import tensorflow as tfimport numpy as npdef make_layer(inputs, in_size, out_size, activate=None):
weights = tf.Variable(tf.random_normal([in_size, out_size]))
basis = tf.Variable(tf.zeros([1, out_size]) + 0.1)
result = tf.matmul(inputs, weights) + basis if activate is None: return result else: return activate(result)class BPNeuralNetwork:
def __init__(self):
self.session = tf.Session()
self.loss = None
self.optimizer = None
self.input_n = 0
self.hidden_n = 0
self.hidden_size = []
self.output_n = 0
self.input_layer = None
self.hidden_layers = []
self.output_layer = None
self.label_layer = None
def __del__(self):
self.session.close() def setup(self, ni, nh, no):
# 设置参数个数
self.input_n = ni
self.hidden_n = len(nh) #隐藏层的数量
self.hidden_size = nh #每个隐藏层中的单元格数
self.output_n = no #构建输入层
self.input_layer = tf.placeholder(tf.float32, [None, self.input_n]) #构建标签层
self.label_layer = tf.placeholder(tf.float32, [None, self.output_n]) #构建隐藏层
in_size = self.input_n
out_size = self.hidden_size[0]
inputs = self.input_layer
self.hidden_layers.append(make_layer(inputs, in_size, out_size, activate=tf.nn.relu)) for i in range(self.hidden_n-1):
in_size = out_size
out_size = self.hidden_size[i+1]
inputs = self.hidden_layers[-1]
self.hidden_layers.append(make_layer(inputs, in_size, out_size, activate=tf.nn.relu)) #构建输出层
self.output_layer = make_layer(self.hidden_layers[-1], self.hidden_size[-1], self.output_n) def train(self, cases, labels, limit=100, learn_rate=0.05):
self.loss = tf.reduce_mean(tf.reduce_sum(tf.square((self.label_layer - self.output_layer)), reduction_indices=[1]))
self.optimizer = tf.train.GradientDescentOptimizer(learn_rate).minimize(self.loss)
initer = tf.initialize_all_variables() #做训练
self.session.run(initer) for i in range(limit):
self.session.run(self.optimizer, feed_dict={self.input_layer: cases, self.label_layer: labels}) def predict(self, case):
return self.session.run(self.output_layer, feed_dict={self.input_layer: case}) def test(self):
x_data = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y_data = np.array([[0, 1, 1, 0]]).transpose()
test_data = np.array([[0, 1]])
self.setup(2, [10, 5], 1)
self.train(x_data, y_data)
print(self.predict(test_data))
nn = BPNeuralNetwork()
nn.test()12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
python能做什么
python的用途:
Python的优势有必要作为第一步去了解,Python作为面向对象的脚本语言,优势就是数据处理和挖掘,这也注定了它和AI、互联网技术的紧密联系。
网络爬虫。顾名思义,从互联网上爬取信息的脚本,主要由urllib、requests等库编写,实用性很强,小编就曾写过爬取5w数据量的爬虫。在大数据风靡的时代,爬虫绝对是新秀。
人工智能。AI使Python一战成名,AI的实现可以通过tensorflow库。神经网络的核心在于激活函数、损失函数和数据,数据可以通过爬虫获得。训练时大量的数据运算又是Python的show time。
扩展资料:
Python开发人员尽量避开不成熟或者不重要的优化。一些针对非重要部位的加快运行速度的补丁通常不会被合并到Python内。在某些对运行速度要求很高的情况,Python设计师倾向于使用JIT技术,或者用使用C/C++语言改写这部分程序。可用的JIT技术是PyPy。
Python是完全面向对象的语言。函数、模块、数字、字符串都是对象。并且完全支持继承、重载、派生、多继承,有益于增强源代码的复用性。
Python支持重载运算符和动态类型。相对于Lisp这种传统的函数式编程语言,Python对函数式设计只提供了有限的支持。有两个标准库(functools, itertools)提供了Haskell和Standard ML中久经考验的函数式程序设计工具。
参考资料来源:百度百科-Python