Python主要是通过标准库threading包来实现多线程。

今天,互联网时代,所有的server您将收到大量请求。

server要利用多线程的方式的优势来处理这些请求,为了改善网络port读写效率。

Python它是一个网络server后台工作语言 (豆瓣网),所以多线程也就非常自然被Python语言支持。

多线程售票以及同步

我们使用Python来实现Linux多线程与同步文中的售票程序。

我们使用mutex (也就是Python中的Lock类对象) 来实现线程的同步:

import threading
import time
import os # This function could be called by any function to do other chores.
def doChore():
time.sleep(0.5) # Function for each thread
def booth(tid):
global i
global lock
while True:
lock.acquire() # Lock; or wait if other thread is holding the lock
if i != 0:
i = i - 1 # Sell tickets
print(tid,':now left:',i) # Tickets left
doChore() # Other critical operations
else:
print("Thread_id",tid," No more tickets")
os._exit(0) # Exit the whole process immediately
lock.release() # Unblock
doChore() # Non-critical operations # Start of the main function
i = 100 # Available ticket number
lock = threading.Lock() # Lock (i.e., mutex) # Start 10 threads
for k in range(10):
new_thread = threading.Thread(target=booth,args=(k,)) # Set up thread; target: the callable (function) to be run, args: the argument for the callable
new_thread.start() # run the thread

这里使用了两个全局变量,一个是i,用以储存剩余票数。一个是lock对象,用于同步线程对i的改动。

此外。在最后的for循环中,我们总共设置了10个线程。

每一个线程都运行booth()函数。

线程在调用start()方法的时候正式启动 (实际上,计算机中最多会有11个线程。由于主程序本身也会占用一个线程)。

Python使用threading.Thread对象来代表线程,用threading.Lock对象来代表一个相互排斥锁 (mutex)。



有两点须要注意:

我们在函数中使用global来声明变量为全局变量,从而让多线程共享i和lock (在C语言中,我们通过将变量放在全部函数外面来让它成为全局变量)。

假设不这么声明,因为i和lock是不可变数据对象。它们将被当作一个局部变量。

假设是可变数据对象的话,则不须要global声明。

我们甚至能够将可变数据对象作为參数来传递给线程函数。

这些线程将共享这些可变数据对象。我们在booth中使用了两个doChore()函数。

能够在未来改进程序。以便让线程除了进行i=i-1之外,做很多其它的操作,比方打印剩余票数,找钱,或者喝口水之类的。

第一个doChore()依旧在Lock内部。所以能够安全地使用共享资源 (critical operations, 比方打印剩余票数)。

第二个doChore()时。Lock已经被释放,所以不能再去使用共享资源。

这时候能够做一些不使用共享资源的操作 (non-critical operation, 比方找钱、喝水)。

这里有益让doChore()等待了0.5秒。以代表这些额外的操作可能花费的时间。

你能够定义的函数来取代doChore()。

OOP创建线程

上面的Python程序很类似于一个面向过程的C程序。

我们以下介绍怎样通过面向对象的方法实现多线程,其核心是继承threading.Thread类。

import threading
import time
import os def doChore():
time.sleep(0.5) # Function for each thread
class BoothThread(threading.Thread):
def __init__(self, tid, monitor):
self.tid = tid
self.monitor = monitor
threading.Thread.__init__(self)
def run(self):
while True:
monitor['lock'].acquire() # Lock; or wait if other thread is holding the lock
if monitor['tick'] != 0:
monitor['tick'] = monitor['tick'] - 1 # Sell tickets
print(self.tid,':now left:',monitor['tick']) # Tickets left
doChore() # Other critical operations
else:
print("Thread_id",self.tid," No more tickets")
os._exit(0) # Exit the whole process immediately
monitor['lock'].release() # Unblock
doChore() # Non-critical operations # Start of the main function
monitor = {'tick':100, 'lock':threading.Lock()} # Start 10 threads
for k in range(10):
new_thread = BoothThread(k, monitor)
new_thread.start()

上面的for循环中已经利用了threading.Thread()的方法来创建一个Thread对象,并将函数booth()以及其參数传递给改对象,并调用start()方法来执行线程。

OOP的话。通过改动Thread类的run()方法来定义线程所要运行的命令。

自定义了一个类BoothThread, 这个类继承自thread.Threading类。

然后我们把上面的booth()所进行的操作统统放入到BoothThread类的run()方法中。

注意。我们没有使用全局变量声明global,而是使用了一个词典monitor存放全局变量,然后把词典作为參数传递给线程函数。

因为词典是可变数据对象。所以当它被传递给函数的时候,函数所使用的依旧是同一个对象,相当于被多个线程所共享。

这也是多线程乃至于多进程编程的一个技巧 (应尽量避免上面的global声明的使用方法,由于它并不适用于windows平台)。

上面OOP编程方法与面向过程的编程方法相比,并没有带来太大实质性的区别。

其它

threading.Thread对象,我们已经介绍了该对象的start()和run(), 此外:

join()方法

调用该方法的线程将等待直到改Thread对象完毕。再恢复执行。这与进程间调用wait()函数相类似。

以下的对象用于处理多线程同步。

对象一旦被建立。能够被多个线程共享,并依据情况堵塞某些进程。

threading.Lock对象

mutex, 有acquire()和release()方法。

threading.Condition对象

condition variable,建立该对象时。会包括一个Lock对象 (由于condition variable总是和mutex一起使用)。

能够对Condition对象调用acquire()和release()方法,以控制潜在的Lock对象。





wait()方法

相当于cond_wait()





notify_all()

相当与cond_broadcast()





nofify()

与notify_all()功能类似,但仅仅唤醒一个等待的线程,而不是所有





threading.Semaphore对象

semaphore,也就是计数锁。

创建对象的时候。能够传递一个整数作为计数上限 (sema = threading.Semaphore(5))。

它与Lock类似,也有Lock的两个方法。

threading.Event对象

与threading.Condition相类似。相当于没有潜在的Lock保护的condition variable。

对象有True和False两个状态。

能够多个线程使用wait()等待。直到某个线程调用该对象的set()方法,将对象设置为True。

线程能够调用对象的clear()方法来重置对象为False状态。

# 最近这些章节并没有看得太清楚如何~~~~~

版权声明:本文博主原创文章,博客,未经同意不得转载。

Python学习笔记16:标准库多线程(threading包裹)的更多相关文章

  1. C++ Primer学习笔记2--c++标准库中的 vector、string 和 bitset 类型

    一.string    #include <string>  using std::string    初始化函数:    string s1;        默认构造函数 s1 为空串 ...

  2. python学习23之标准库

    '''''''''标准库1.datetime 日期时间模块存在于Lib/datetime.py文件内'''from datetime import datetime,date,time #from d ...

  3. C++ Primer 学习笔记_6_标准库类型 -- 命名空间using与string类型

     标准库类型(一) --命名空间using与string类型 引: 标准库类型是语言组成部分中更主要的哪些数据类型(如:数组.指针)的抽象! C++标准库定义的是高级的抽象数据类型: 1.高级:由 ...

  4. Python 3 学习笔记之——标准库概述

    1. 操作系统接口 os 模块提供了一些与操作系统相关联的函数. >>> os.getcwd() # 获取当前工作目录 '/home/senius' >>> os. ...

  5. Python学习笔记(三)多线程的使用

    这节记录学习多线程的心得.   Python提供了thread模块,不过该模块的缺点很多,例如无法方便的等待线程结束,所以我们使用更加高级的threading模块.   threading模块的使用一 ...

  6. 吴裕雄--天生自然python学习笔记:beautifulsoup库的使用

    Beautiful Soup 库简介 Beautiful Soup提供一些简单的.python式的函数用来处理导航.搜索.修改分析树等功能.它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简 ...

  7. Python学习笔记16—电子表格

    openpyl 模块是解决 Microsoft Excel 2007/2010 之类版本中扩展名是 Excel 2010 xlsx/xlsm/xltx/xltm 的文件的读写的第三方库. 安装 pip ...

  8. Python学习笔记之——requests库

    requests库一个优雅而简单的用于Python的HTTP库,可以极大的简化我们发送http请求及获取响应的代码. requests是python的第三方库,所以使用之前需要先安装. 1.安装之后就 ...

  9. python学习笔记(自定义库文件路径)

    博主最近在弄接口自动化.主要是基于python自带的unittest框架.包括 Pubilc模块定义所有接口. Main模块根据业务需求重新封装接口便于测试. config文件导入测试业务的固定参数. ...

随机推荐

  1. 【Linux探索之旅】开宗明义+第一部分第一课:什么是Linux?

    内容简介 1.课程大纲 2.第一部分第一课:什么是Linux? 3.第一部分第二课预告:下载Linux,免费的噢!   开宗明义 我们总听到别人说:Linux挺复杂的,是给那些追求逼格的程序员用的.咱 ...

  2. Uncaught TypeError: Cannot read property &#39;call&#39; of undefined jquery.validate.min.js:28

    最近在做表单验证时,,自己写的addMethod 方法总是不起作用.折腾了将近一天. 报告的错误,如下面的 Uncaught TypeError: Cannot read property 'call ...

  3. 【Android基础】Activity之间进行参数传递的三种方式

    1.使用Intent进行传输 //发送数据的Activity class button implements OnClickListener{ @Override public void onClic ...

  4. python基础课程_学习笔记26:编程的乐趣

    编程的乐趣 编程柔术 当你坐下来,打算如何组织计划要定时,具体程序,然而,无论什么经验.在实现时间的函数的,你会逐渐学会了原来的设计,实用的新知识.我们不应该忽视沿途汲取的教训,相反,它们用于其他设计 ...

  5. 关于苹果公司最新的语言Swift

    Swift供IOS和OSX新的编程语言开发的应用程序,吸取C和Objective-C质朴的语言.但没有损失C兼容性语言.Swift使用安全的编程模型.增加各种现代编程语言功能,使语言更容易掌握.更具可 ...

  6. iOS当该装置是水平屏,frame和bounds分别

    project那里有两个ViewControllers.间ViewController它是root view controller,红色背景,有一个顶button,点击加载后GreenViewCont ...

  7. C#枚举数和迭代器

    大道至简,始终认为简洁是一门优秀的编程语言的一个必要条件.相对来说,C#是比较简洁的,也越来越简洁.在C#中,一个关键字或者语法糖在编译器层面为我们做了很多乏味的工作,可能实现的是一个设计模式,甚至是 ...

  8. 理解Android虚拟机体系结构(转)

    1 什么是Dalvik虚拟机 Dalvik是Google公司自己设计用于Android平台的Java虚拟机,它是Android平台的重要组成部分,支持dex格式(Dalvik Executable)的 ...

  9. 据序和中序序列或者也许为了一个二进制序列,恢复二进制和打印图像(c语言)

    首先要预购和序,以恢复它: 1.首先,我们使用的是递归的方式来完成 2.递归的最小单位:一个空的树和书的前言和第一序.该序列的第一个元素是树的第一序列根,调用这种方法 3.递归的终止条件是.当这棵树的 ...

  10. Log4NET 数据库

    阅读目录 Log4NET简介 前提 详细步骤 回到顶部 Log4NET简介 log4net库是Apache log4j框架在Microsoft .NET平台的实现,是一个帮助程序员将日志信息输出到各种 ...