Python之多线程

2016-09-05  本文已影响138人  yang2yang

什么是线程?

要弄清楚线程的定义,往往就要和进程相互比较,从比较中才能更准确地明白一个东西的定义。首先有个数量关系是这样的,进程是由多线程组成的,每个进程起码都有一个线程
然后重点是有人说:

进程和线程简单而基本靠谱的定义如下:
1. 进程:程序的一次执行
2. 线程:CPU的基本调度单位

给一句话的定义,其实没有什么意思。但是,做为最根本的落脚点,放着也是极好的。
阮大神的这篇blog写的很通俗,但是不清楚,不深入,但是文章加评论却是相当有意思。

在我眼中的定义的理解

Python的多线程实现(Python3实现)

Python的标准库提供了两个模块:_threadthreading_thread是低级模块,threading是高级模块,对_thread进行了封装。绝大多数情况下,我们只需要使用threading这个高级模块。
下面是廖大官网的例子,感觉非常不错,搬过来了哈。

import time, threading

# 假定这是你的银行存款:
balance = 0

def change_it(n):
    # 先存后取,结果应该为0:
    global balance
    balance = balance + n
    balance = balance - n

def run_thread(n):
    for i in range(100000):
        change_it(n)

t1 = threading.Thread(target=run_thread, args=(5,))
t2 = threading.Thread(target=run_thread, args=(8,))
t1.start()
t2.start()
t1.join()
t2.join()
print(balance)

如果是初次在学校中开始接触到线程的话,其实有一点是十分困惑的。(反正我是非常困惑的)就是有一种欲望是想看看threading这个模块的Thread函数的实现是什么?或者说就想弄清楚,弄明白run_thread,这个函数命传递进去了之后,程序代码到底做了什么?为什么要t1.start()t1.join()?就很奇怪,一个好好的函数,为什么要target传一个函数名,args参数传函数的参数,一起传不好吗?

然后当你真的点击去看实现的时候,就会一脸懵逼。那么如果控制这种想法呢?反正我就明白一点就是,学习的过程,并不是你前面的都明白的,下一个点也能明白的,有时候明白这种明白,知道这个点不是现阶段的问题这个事实是非常好的。

API中的几个注意点:

  1. target传递的是一个函数名,而不是函数调用,如果你看过Python的线程的API的话,也是要注意这一点的。
  2. balance这种全局变量是可以被所有线程访问到的。然后就有了锁的概念,那不是另一个世界了。
  3. 线程的start()join()函数的作用,线程的调度是由操作系统决定的,没有先后顺序,高级语言的有些一条语句其实可以拆分之类的概念,这里是不会提的,不然显得没重点,可以看一下廖大的教程,很详细。
  4. 下面是其中一种运行结果。
初始值 balance = 0

t1: x1 = balance + 5  # x1 = 0 + 5 = 5

t2: x2 = balance + 8  # x2 = 0 + 8 = 8
t2: balance = x2      # balance = 8

t1: balance = x1      # balance = 5
t1: x1 = balance - 5  # x1 = 5 - 5 = 0
t1: balance = x1      # balance = 0

t2: x2 = balance - 8  # x2 = 0 - 8 = -8
t2: balance = x2   # balance = -8

结果 balance = -8
balance = 0
lock = threading.Lock()

def run_thread(n):
    for i in range(100000):
        # 先要获取锁:
        lock.acquire()
        try:
            # 放心地改吧:
            change_it(n)
        finally:
            # 改完了一定要释放锁:
            lock.release()

还真是,这个API比JAVA中的要简单很多。

GIL

GIL是全局解释器锁,可以看这个东西的英文比较能懂。因为这个东西的存在,Python的多线程,不论怎么样都只能充分使用CPU的一个核心。有下面几点要注意:

  1. Python是一种语言,语言也可以理解为一种语法标准,在这个标准里面是没有GIL的,但是这个语言的实现,官方的解释去CPython中是用了GIL来实现的,但是比如JPython是没有这个概念的。(那么问题来了,为什么还是有那么多人使用CPython?)
  2. Python3中的GIL也是一样存在的,只是Python3中对GIL的一个多线程比单线程还要慢的这一个问题进行了修复,没有从根本上解决这个问题。
  3. 想充分利用多核CPU的话,可以使用多进程。(那么为什么多进程可以避开GIL而充分使用CPU呢?)

最后之前

为什么多线程或者说多进程会比单进程快呢?对于IO密集型,计算密集型?可以从CPU和操作系统的角度来谈谈这个问题吗?计算机有几个IO方式呢,比如DMA是什么,有什么不同?计算机IO的时候,是需要CPU的运行吗?需要吗?不需要吗?不需要的话,又是谁把磁盘中的数据读到内存中的呢?除了CPU还有谁有这个能力呢?线程和进程在CPU这个层面到底是什么瓜葛呢?待我好好看书,来回答这个问题。

最后

写给未来的自己,也写给读到最后的你,能力有限,如有错误,请交流谈论及指正,如果有帮助,请评论或者点击喜欢,谢谢。

参考:

进程与线程的一个简单解释
廖雪峰的官方教程之多线程
Python 之父谈 Python
Python 3.2与更好的GIL

上一篇 下一篇

猜你喜欢

热点阅读