资讯专栏INFORMATION COLUMN

python学习笔记- 多线程

RiverLi / 443人阅读

摘要:也提供多线程支持,而且中的线程并非是模拟出来的多线程,而是系统级别的标准库提供了两个模块和。同一个变量,线程则会互相共享。例如多个线程对银行中的某一个账户进行操作。但是实际情况是随意切换线程。说到的多线程编程,就会绕不过。

该文章参考了http://www.liaoxuefeng.com/wi... 廖雪峰的教程。

一个进程至少有一个线程。
Python也提供多线程支持,而且Python中的线程并非是模拟出来的多线程,而是系统级别的Posix Thread.

Python标准库提供了两个模块threadthreading。前者是低级库,后者是高级库。高级库是对低级库的封装。
通常情况下,我们只需要使用threading高级库就可以了。

如何创建Thread

我们只需要创建threading.Thread类,并传入一个需要线程执行的函数作为target即可。

import threading

import time


def loop():
    count = 1
    while count < 4:
        print "Hello"
        time.sleep(1)
        count += 1


if __name__ == "__main__":
    thread = threading.Thread(target=loop, name="LoopThread")
    thread.start()
    thread.join()
    current_thread = threading.current_thread()
    print current_thread.getName()
    print "LoopThread Ended"

上述代码主进程默认会创建一个主线程。
上面的代码中,我们用到了多个函数。

join()函数:即让主线程序等待子线程完成后继续。

current_thread()函数:获取当前线程的实例。

Lock 锁

同一个变量,进程会拷贝一份存于各个进程中,互不影响。
同一个变量,线程则会互相共享。这就会带来一些问题。因为cpu对线程是随意切换的。那么如果一个线程对某一个变量进行多步cpu操作的时候,如果不加锁,那么可能会在线程进行到一半的时候,会被切换到其他线程,从而使得操作变乱。
一个典型的例子是“一存一取”的场景。
例如多个线程对银行中的某一个账户进行操作。一个线程需要对账户进行一存一取某一个金额的操作才会让账户平衡。
但是多个线程对该账户进行操作的时候,且它们操作的金额经常是不一样的,那么最终的账户很可能是不平衡的。

thread 1: -100
thread 1: +100

thread 1: -100
thread 1: +100

thread 2: -200
thread 2: +200

thread 2: -200
thread 2: +200

上述描述了两个线程按顺序互补干扰地对某一个账户进行操作。
但是实际情况是cpu随意切换线程。上述操作是打乱的,例如

thread 1: -100
thread 2: -200
thread 2: +200
...

此时,我们发现账户并不是平衡的。
如果解决呢?我们需要对每一个thread的一存一取操作加一把锁。即改账户变量必须是让一个线程先进行完整的一存一取操作后,才能被其他线程所操作。

我们可以将要上锁的代码包裹起来,即:

    lock.acquire()
    num = num + n
    num = num - n
    print num
    lock.release()

当然,lock可以对资源的获取和释放,那么我们也可以用with关键字。

with lock:
    num = num + n
    num = num - n
    print num
死锁 deadlock

死锁的发生往往是两个线程各自占用了对方所需要用到的资源而都在等待对方释放资源而造成的。
遇见死锁后,程序则会一直暂停在那里。直到系统将它们关闭。

GIL

说到Python的多线程编程,就会绕不过GIL。那么GIL又是什么鬼呢?
GIL据说是Python中hardest的问题,想要彻底了解GIL,必须要对操作系统设计、多线程编程、C语言、解释器设计和CPython解释器的实现有着非常彻底的理解。

据廖雪峰中的教程中描述:

Python中的线程虽然是真正的线程,但是解释器执行代码的时候,会有一个GIL锁(Global Interpreter Lock). 任何Python线程执行前,必须先获得GIL锁。然后,每执行100条字节码,解释器就会自动释放GIL锁,让别的线程有机会执行。这个GIL全局锁实际上把所有线程的执行代码都给上了锁。因此,多线程在Python中只能交替进行,即使100个线程跑在100核CPU上,也只能用到1个核心。

GIL是Python解释器设计的历史遗留问题,通常我们用的解释器是官方实现彻底CPython。

更多关于GIL设计的历史渊源,可以阅读:

http://cenalulu.github.io/pyt...

http://www.oschina.net/transl...

那么是不是Python就是不能利用多核处理器任务了呢?我们之前学到过多进程编程,每一个进程都有一个独立的GIL锁,各进程互不影响。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/38366.html

相关文章

  • Python

    摘要:最近看前端都展开了几场而我大知乎最热语言还没有相关。有关书籍的介绍,大部分截取自是官方介绍。但从开始,标准库为我们提供了模块,它提供了和两个类,实现了对和的进一步抽象,对编写线程池进程池提供了直接的支持。 《流畅的python》阅读笔记 《流畅的python》是一本适合python进阶的书, 里面介绍的基本都是高级的python用法. 对于初学python的人来说, 基础大概也就够用了...

    dailybird 评论0 收藏0
  • Python学习笔记:Web后端开发一览

    摘要:试想,在多线程服务器中,多个线程同时处理不同客户端发送的不同请求时,每个线程看到的对象必然不同。多线程服务器会创建一个线程池,再从线程池中选择一个线程用于处理接收到的请求。 框架 Django flask flask是一个轻量的web开发应用示例开发一个小应用 from flask import Flask app = Flask(__name__) @app.route(/) d...

    DrizzleX 评论0 收藏0
  • python学习笔记 - ThreadLocal

    摘要:为了避免改乱为,我们在前面已经提到说要加锁。仅供一个线程使用,线程间相互不影响。例如下列程序中函数中定义的变量就是局部变量。所有绑定的参数都是线程隔离的。下面展示一下代码创建一个全局的对象初始化一个线程内变量,该变量线程间互不影响。 我们在编写多线程程序的时候,往往会遇到两种类型的变量。 一种是全局变量,多个线程共享。为了避免改乱为,我们在前面已经提到说要加锁。 一种是局部变量。仅供...

    Berwin 评论0 收藏0
  • Python - 收藏集 - 掘金

    摘要:首发于我的博客线程池进程池网络编程之同步异步阻塞非阻塞后端掘金本文为作者原创,转载请先与作者联系。在了解的数据结构时,容器可迭代对象迭代器使用进行并发编程篇二掘金我们今天继续深入学习。 Python 算法实战系列之栈 - 后端 - 掘金原文出处: 安生    栈(stack)又称之为堆栈是一个特殊的有序表,其插入和删除操作都在栈顶进行操作,并且按照先进后出,后进先出的规则进行运作。 如...

    546669204 评论0 收藏0
  • 那些年我看过的书 —— 致敬我的大学生活 —— Say Good Bye !

    摘要:开头正式开启我入职的里程,现在已是工作了一个星期了,这个星期算是我入职的过渡期,算是知道了学校生活和工作的差距了,总之,尽快习惯这种生活吧。当时是看的廖雪峰的博客自己也用做爬虫写过几篇博客,不过有些是在前人的基础上写的。 showImg(https://segmentfault.com/img/remote/1460000010867984); 开头 2017.08.21 正式开启我...

    xiaoqibTn 评论0 收藏0

发表评论

0条评论

RiverLi

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<