咱们都知道计算机是由硬件和软件组成的。硬件中的CPU是计算机的核心,它承担计算机的全部任务。 操做系统是运行在硬件之上的软件,是计算机的管理者,它负责资源的管理和分配、任务的调度。 程序是运行在系统上的具备某种功能的软件,好比说浏览器,音乐播放器等。 每次执行程序的时候,都会完成必定的功能,好比说浏览器帮咱们打开网页,为了保证其独立性,就须要一个专门的管理和控制执行程序的数据结构——进程控制块。 进程就是一个程序在一个数据集上的一次动态执行过程。 进程通常由程序、数据集、进程控制块三部分组成。咱们编写的程序用来描述进程要完成哪些功能以及如何完成;数据集则是程序在执行过程当中所须要使用的资源;进程控制块用来记录进程的外部特征,描述进程的执行变化过程,系统能够利用它来控制和管理进程,它是系统感知进程存在的惟一标志。
在早期的操做系统里,计算机只有一个核心,进程执行程序的最小单位,任务调度采用时间片轮转的抢占式方式进行进程调度。每一个进程都有各自的一块独立的内存,保证进程彼此间的内存地址空间的隔离。 随着计算机技术的发展,进程出现了不少弊端,一是进程的建立、撤销和切换的开销比较大,二是因为对称多处理机(对称多处理机(SymmetricalMulti-Processing)又叫SMP,是指在一个计算机上聚集了一组处理器(多CPU),各CPU之间共享内存子系统以及总线结构)的出现,能够知足多个运行单位,而多进程并行开销过大。 这个时候就引入了线程的概念。 线程也叫轻量级进程,它是一个基本的CPU执行单元,也是程序执行过程当中的最小单元,由线程ID、程序计数器、寄存器集合 和堆栈共同组成。线程的引入减少了程序并发执行时的开销,提升了操做系统的并发性能。 线程没有本身的系统资源,只拥有在运行时必不可少的资源。但线程能够与同属与同一进程的其余线程共享进程所拥有的其余资源。
进程与线程之间的关系
线程是属于进程的,线程运行在进程空间内,同一进程所产生的线程共享同一内存空间,当进程退出时该进程所产生的线程都会被强制退出并清除。线程可与属于同一进程的其它线程共享进程所拥有的所有资源,可是其自己基本上不拥有系统资源,只拥有一点在运行中必不可少的信息(如程序计数器、一组寄存器和栈)。
python 线程
Threading用于提供线程相关的操做,线程是应用程序中工做的最小单元。
一、threading模块
threading 模块创建在 _thread 模块之上。thread 模块以低级、原始的方式来处理和控制线程,而 threading 模块经过对 thread 进行二次封装,提供了更方便的 api 来处理线程。
上述代码建立了20个“前台”线程,而后控制器就交给了CPU,CPU根据指定算法进行调度,分片执行指令。
Thread方法说明
t.start() : 激活线程,
t.getName() : 获取线程的名称
t.setName() : 设置线程的名称
t.name : 获取或设置线程的名称
t.is_alive() : 判断线程是否为激活状态
t.isAlive() :判断线程是否为激活状态
t.setDaemon() 设置为后台线程或前台线程(默认:False);经过一个布尔值设置线程是否为守护线程,必须在执行start()方法以后才可使用。若是是后台线程,主线程执行过程当中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均中止;若是是前台线程,主线程执行过程当中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序中止
t.isDaemon() : 判断是否为守护线程
t.ident :获取线程的标识符。线程标识符是一个非零整数,只有在调用了start()方法以后该属性才有效,不然它只返回None。
t.join() :逐个执行每一个线程,执行完毕后继续往下执行,该方法使得多线程变得无心义
t.run() :线程被cpu调度后自动执行线程对象的run方法
二、线程锁threading.RLock和threading.Lock
因为线程之间是进行随机调度,而且每一个线程可能只执行n条执行以后,CPU接着执行其余线程。为了保证数据的准确性,引入了锁的概念。因此,可能出现以下问题:
例:假设列表A的全部元素就为0,当一个线程从前向后打印列表的全部元素,另一个线程则从后向前修改列表的元素为1,那么输出的时候,列表的元素就会一部分为0,一部分为1,这就致使了数据的不一致。锁的出现解决了这个问题。
import threading
import time
globals_num = 0
lock = threading.RLock()
def Func():
for i in range(10):
三、threading.RLock和threading.Lock 的区别
RLock容许在同一线程中被屡次acquire。而Lock却不容许这种状况。 若是使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,必须调用n次的release才能真正释放所占用的琐。
import threading
lock = threading.Lock() #Lock对象
lock.acquire()
lock.acquire() #产生了死琐。
lock.release()
lock.release()
import threading
rLock = threading.RLock() #RLock对象
rLock.acquire()
rLock.acquire() #在同一线程内,程序不会堵塞。
rLock.release()
rLock.release()
四、threading.Event
python线程的事件用于主线程控制其余线程的执行,事件主要提供了三个方法 set、wait、clear。
事件处理的机制:全局定义了一个“Flag”,若是“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,若是“Flag”值为True,那么event.wait 方法时便再也不阻塞。
import threading
def do(event):
event_obj = threading.Event()
for i in range(10):
event_obj.clear()
inp = input('input:')
if inp == 'true':
当线程执行的时候,若是flag为False,则线程会阻塞,当flag为True的时候,线程不会阻塞。它提供了本地和远程的并发性。
五、threading.Condition
一个condition变量老是与某些类型的锁相联系,这个可使用默认的状况或建立一个,当几个condition变量必须共享和同一个锁的时候,是颇有用的。锁是conditon对象的一部分:没有必要分别跟踪。
condition变量服从上下文管理协议:with语句块封闭以前能够获取与锁的联系。 acquire() 和 release() 会调用与锁相关联的相应的方法。
其余和锁关联的方法必须被调用,wait()方法会释放锁,当另一个线程使用 notify() or notify_all()唤醒它以前会一直阻塞。一旦被唤醒,wait()会从新得到锁并返回,
Condition类实现了一个conditon变量。 这个conditiaon变量容许一个或多个线程等待,直到他们被另外一个线程通知。 若是lock参数,被给定一个非空的值,,那么他必须是一个lock或者Rlock对象,它用来作底层锁。不然,会建立一个新的Rlock对象,用来作底层锁.
•wait(timeout=None) : 等待通知,或者等到设定的超时时间。当调用这wait()方法时,若是调用它的线程没有获得锁,那么会抛出一个RuntimeError 异常。 wati()释放锁之后,在被调用相同条件的另外一个进程用notify() or notify_all() 叫醒以前 会一直阻塞。wait() 还能够指定一个超时时间。
若是有等待的线程,notify()方法会唤醒一个在等待conditon变量的线程。notify_all() 则会唤醒全部在等待conditon变量的线程。
注意: notify()和notify_all()不会释放锁,也就是说,线程被唤醒后不会马上返回他们的wait() 调用。除非线程调用notify()和notify_all()以后放弃了锁的全部权。
在典型的设计风格里,利用condition变量用锁去通许访问一些共享状态,线程在获取到它想获得的状态前,会反复调用wait()。修改状态的线程在他们状态改变时调用 notify() or notify_all(),用这种方式,线程会尽量的获取到想要的一个等待者状态。 例子: 生产者-消费者模型,
import threading
import time
def consumer(cond):
def producer(cond):
condition = threading.Condition()
c1 = threading.Thread(name="c1", target=consumer, args=(condition,))
c2 = threading.Thread(name="c2", target=consumer, args=(condition,))
p = threading.Thread(name="p", target=producer, args=(condition,))
c1.start()
time.sleep(2)
c2.start()
time.sleep(2)
p.start()
六、queue模块
Queue 就是对队列,它是线程安全的
举例来讲,咱们去麦当劳吃饭。饭店里面有厨师职位,前台负责把厨房作好的饭卖给顾客,顾客则去前台领取作好的饭。这里的前台就至关于咱们的队列。造成管道样,厨师作好饭经过前台传送给顾客,所谓单向队列
这个模型也叫生产者-消费者模型。
import queue
q = queue.Queue(maxsize=0)
q.join()
q.qsize()
q.empty()
q.full()
q.put(item, block=True, timeout=None) #
为False时为非阻塞,此时若是队列已满,会引起queue.Full 异常。 可选参数timeout,表示 会阻塞设置的时间,事后,
q.get(block=True, timeout=None) #
若此时队列为空,则引起 queue.Empty异常。 可选参数timeout,表示会阻塞设
置的时候,事后,若是队列为空,则引起Empty异常。
q.put_nowait(item) #
q.get_nowait() #
代码以下:
#!/usr/bin/env python
import Queue
import threading
message = Queue.Queue(10)
def producer(i):
def consumer(i):
for i in range(12):
for i in range(10):
那就本身作个线程池吧:
方法一
# 简单往队列中传输线程数
import threading
import time
import queue
class Threadingpool():
def func(p,i):
if __name__ == "__main__":
方法二
#往队列中无限添加任务
import queue
import threading
import contextlib
import time
StopEvent = object()
class ThreadPool(object):