python --- 基础多线程编程
在python中进行多线程编程之前必须了解的问题:
1. 什么是线程?
答:线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。
2. 什么是多线程?
答:在单个程序中同时运行多个线程完成不同的工作,称为多线程。
3. 多线程编程的目的?
答:多线程是为了同步完成多项任务,不是为了提高运行效率,而是为了提高资源使用效率来提高系统的效率。线程是在同一时间需要完成多项任务的时候实现的。
4. 如何再python中执行多线程编程?
答:在python2.x的版本中提供了thread(这个模块为多线程提供了一个底层 、原始的操作[也可以成为light-weight processes 或者 tasks) — 多个控制线程共享全局数据空间。为了多线程同步,提供了简单的锁(也称呼为 mutexes 后者 binary semaphores) 。]和threading(本模块的高层线程接口构建在低层的thread模块上)两个模块用于线程操作;而在python3.x中,官方只给出了threading模块的文档,对于底层线程造作放在了_thread模块中(即不建议使用)。是故在python中使用threading模块编程即可。
例一(一个简单的双线程程序):
import threading
import time def run(n):
print("task-%s" % n)
time.sleep(5) #实例化一个线程对象,target传入任务名,args以元组的形式传入任务函数的参数
task1 = threading.Thread(target=run, args=(1,))
task2 = threading.Thread(target=run, args=(2,)) task1.start() #线程启动
task2.start()
test_threads_1
注:执行上面这个程序一共花费5秒左右的时间,而如果分别调用两次run怎需要10秒(证明两个任务同时运行)。
例二(用面向对象编程实现例二,并讲解threading模块中的一些常用方法):
import threading
import time class Task(threading.Thread):
def __init__(self, n):
super(Task, self).__init__() #重构了__init__(), 所以先执行父类的构造函数
self.n = n #构造函数中传入任务参数参数 #任务函数
def run(self):
"""
不同于例一,在类中,任务函数只能以run命名,参数从构造函数中传入
:return:
"""
print("task-%s" % self.n)
# print(threading.current_thread()) #threading.current_thread()返回当前的Thread对象,对应于调用者控制的线程。
time.sleep(2) #实例化并启动
t1 = Task(1)
t2 = Task(2)
# t1.setDaemon(True) #将t1设置成为守护线程
# t2.setDaemon(True) t1.start()
#t1.join(timeout=5) #等待t1结束再运行t2,timeout代表等待时间,超过5秒便不再等待。
t2.start() # print(threading.current_thread())
# print(threading.active_count()) #threading.active_count()返回当前处于alive状态的Thread对象的个数。
test_threads_2
注:建议使用例二这种编程方式,在类中,任务函数只能以run命名,参数从构造函数中传入。
注:有时候难免会遇到一个问题,主程序的执行需要某个子线程(即使用start启动的线程,默认子线程一旦启动主程序将继续运行,两者不再有关联)的执行结果,这时使用join即可,例如例二中的t1.join()。
守护线程:一种特殊的子线程,与主线程(即本文中的主程序,由程序使用者启动)存在一种“主死仆死”的关系,即主线程意外停止或运行结束,不管守护线程是否运行完毕都得终止(非守护线程的子线程启动后与主线程没有联系,不论主线程是否还在运行,子线程不受影响),一个线程是否为守护线程继承于创建它的线程(将一个子线程设置成为守护线程可参考例二,去掉22,23行注释,则主程序结束t1,t2也结束,不会再sleep)。
在进行多线程编程时,经常会有多个线程同时对同一份数据修改,这便会导致最终得得到的数据不是预期结果。所以需要在一个线程修改数据时将数据锁定,只允许当前线程修改,当修改完成后,解锁让其他线程修改。在threading模块中使用Lock Objects解决此问题。
Lock Objects:
A primitive lock is a synchronization primitive that is not owned by a particular thread when locked. In Python, it is currently the lowest level synchronization primitive available, implemented directly by the _thread
extension module.
A primitive lock is in one of two states, “locked” or “unlocked”. It is created in the unlocked state. It has two basic methods, acquire()
and release()
. When the state is unlocked, acquire()
changes the state to locked and returns immediately. When the state is locked, acquire()
blocks until a call to release()
in another thread changes it to unlocked, then the acquire()
call resets it to locked and returns. The release()
method should only be called in the locked state; it changes the state to unlocked and returns immediately. If an attempt is made to release an unlocked lock, a RuntimeError
will be raised.
Locks also support the context management protocol.
When more than one thread is blocked in acquire()
waiting for the state to turn to unlocked, only one thread proceeds when a release()
call resets the state to unlocked; which one of the waiting threads proceeds is not defined, and may vary across implementations.
All methods are executed atomically.
例三(多个线程对一个全局变量进行加1操作):
import threading,time n = 5 class Task(threading.Thread):
def __init__(self, n):
super(Task, self).__init__()
self.name = "Thread-" + str(n) def run(self):
"""
不同于例一,在类中,任务函数只能以run命名,参数从构造函数中传入
:return:
"""
global n
time.sleep(0.5)
#锁定资源, 此时关于n的操作只能此线程执行
if lock.acquire():
n += 1
print("%s, n = %s" % (self.name, n))
time.sleep(0.2)
lock.release() #解锁 if __name__ == "__main__": lock = threading.Lock() #实例化一个锁,此时锁处于打开状态 ts = [] #用于存储线程对象
#循环启动50个线程
for i in range(1, 50+1):
t = Task(i)
ts.append(t)
t.start()
#等待所有线程结束
start_time = time.time()
for t in ts:
t.join() print("run time:",time.time() - start_time)
test_threads_3
注:运行此程序,可发现一共用时10.5(0.2*50 + 0.5)秒左右,可以发现在锁定代码段程序没有并行执行。
注:有时候需要多层加锁,这时Lock Objects已经满足不了这个需求(当Lock处于locked时,遇到下一个acquire()时会阻塞)。这时我们使用RLock Objects,它的调用同Lock Objects。
信号量:信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。
举例说明:以一个停车场的运作为例。简单起见,假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,看门人允许其中三辆直接进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。这时,有一辆车离开停车场,看门人得知后,打开车拦,放入外面的一辆进去,如果又离开两辆,则又可以放入两辆,如此往复。
import threading
import time class Task(threading.Thread):
#任务函数
def __init__(self, n):
super(Task, self).__init__()
self.name = "Thread-" + str(n) def run(self):
semaphore.acquire()
print("%s" % self.name)
time.sleep(2)
semaphore.release() if __name__ == "__main__": semaphore = threading.BoundedSemaphore(5) #只允许5个线程同时访问资源 ts = [] #用于存储线程对象
#循环启动50个线程 for i in range(1, 23+1):
t = Task(i)
ts.append(t)
t.start()
test_threads_4
An event object manages an internal flag that can be set to true with the set()
method and reset to false with the clear()
method. The wait()
method blocks until the flag is true(每个事件对象管理一个内部标志,可以在事件对象上调用set()
方法将内部标志设为true,调用 clear()
方法将内部标志重置为false。wait()
方法将阻塞直至该标志为真。).
例五(简单的线程交互程序,演示Event Objects的使用):
import threading,time class Task1(threading.Thread):
def run(self):
while True:
for i in range(1, 20+1):
print("i = ", i)
if i % 5 == 0:
eve.set() #到5的倍数,将Event内部标志设置为True
time.sleep(0.5) class Task2(threading.Thread):
def run(self):
while True:
#检测内部标志是否为True
if eve.is_set():
print("hello world")
time.sleep(2)
eve.clear() #重置Event内部标志
else:
eve.wait() #内部标志不为True,此线程处于阻塞状态 if __name__ == "__main__":
t1 = Task1()
t2 = Task2()
eve = threading.Event() #实例化一个Event Objects t1.start()
t2.start()
test_threads_5
python --- 基础多线程编程的更多相关文章
- python基础-函数式编程
python基础-函数式编程 高阶函数:map , reduce ,filter,sorted 匿名函数: lambda 1.1函数式编程 面向过程编程:我们通过把大段代码拆成函数,通过一层一层 ...
- python基础——面向对象编程
python基础——面向对象编程 面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的 ...
- python 基础网络编程2
python 基础网络编程2 前一篇讲了socketserver.py中BaseServer类, 下面介绍下TCPServer和UDPServer class TCPServer(BaseServer ...
- python 基础网络编程1
python 基础网络编程1 Source code: Lib/socketserver.py lib的主目录下有一个sockserver.py文件, 里面是python基本的网络编程模型 共有一个b ...
- Python的多线程编程
提到多线程,很多人就会望而却步,本文将由浅入深地带你攻克python多线程编程,并防止你跳入深坑, 首先看一段简单的代码: from time import ctime,sleep def play_ ...
- python基础网络编程--转
python之网络编程 本地的进程间通信(IPC)有很多种方式,但可以总结为下面4类: 消息传递(管道.FIFO.消息队列) 同步(互斥量.条件变量.读写锁.文件和写记录锁.信号量) 共享内存(匿名的 ...
- 【转】使用python进行多线程编程
1. python对多线程的支持 1)虚拟机层面 Python虚拟机使用GIL(Global Interpreter Lock,全局解释器锁)来互斥线程对共享资源的访问,暂时无法利用多处理器的优势.使 ...
- Python基础-socket编程
一.网络编程 自从互联网诞生以来,现在基本上所有的程序都是网络程序,很少有单机版的程序了. 计算机网络就是把各个计算机连接到一起,让网络中的计算机可以互相通信.网络编程就是如何在程序中实现两台计算机的 ...
- python基础和编程库
Python编程从入门到实践-------基础入门 1.Python中的变量 2.Python首字母大写使用title()方法,全部大写upper()方法,全部小写lower()方法 3.Python ...
随机推荐
- Python中function(函数)和methon(方法)的区别
在Python中,对这两个东西有明确的规定: 函数function —— A series of statements which returns some value to a caller. It ...
- python语言学习笔记整理
什么是程序? 程序等于数据结构加算法,那么数据结构是一个静态的东西,算法是一个动态的东西,我们用一个新的语言编写这个程序,我们要考虑到语言也主要由数据结构和算法相关的东西,或静态或动态的东西来构成,所 ...
- python 单下划线/双下划线使用总结
文章转自:http://blog.csdn.net/pfm685757/article/details/45918575
- mysql5.7 设置远程访问
mysql5.7设置远程访问不是和网上说的一样建个用户赋个权限就可以访问的.比如下边这个就是建用户赋权限,可能在之前的版本可以,但是我在我的mysql上一直不行.为此烦了好久!!!项目都耽误了!! 一 ...
- Video Target Tracking Based on Online Learning—TLD单目标跟踪算法详解
视频目标跟踪问题分析 视频跟踪技术的主要目的是从复杂多变的的背景环境中准确提取相关的目标特征,准确地识别出跟踪目标,并且对目标的位置和姿态等信息精确地定位,为后续目标物体行为分析提供足 ...
- datalist标签小结
在Web设计中,经常会用到如输入框的自动下拉提示,这将大大方便用户的输入.在以前,如果要实现这样的功能,必须要求开发者使用一些Javascript的技巧或相关的框架进行ajax调用,需要一定的编程工作 ...
- html笔记3
继续记录 继续上次的img标签 <html> <body style="font-famliy:arial"> <img src="1.jp ...
- [国嵌攻略][159][SPI子系统]
SPI 子系统架构 1.SPI core核心:用于连接SPI客户驱动和SPI主控制器驱动,并且提供了对应的注册和注销的接口. 2.SPI controller driver主控制器驱动:用来驱动SPI ...
- POJ 3278 Catch That Cow(模板——BFS)
题目链接:http://poj.org/problem?id=3278 Description Farmer John has been informed of the location of a f ...
- LNMP 与 LAMP 架构的区别及配置解决方案
2014-12-31 10:33| 发布者: digitser| 查看: 5618| 评论: 0|原作者: liangsheng 摘要: LNMP 与 LAMP 架构的区别及配置解决方案 LNMP 的 ...