Python基础第25天
进程与线程
一:进程(process)
一个程序在一个数据集上的一次动态执行过程。
进程有很多优点,它提供了多道编程,让我们感觉我们每个人都拥有自己的CPU和其他资源,可以提高计算机的利用率,,其实,仔细观察就会发现进程还是有很多缺陷的,主要体现在以下两点上:
1.进程只能在一个时间干一件事,不能同时干两件事或多件事。
2.进程在执行的过程中如果有阻塞,例如:等待输入,整个进程就会挂起,即使进程中有些工作不依赖与输入的数据,也无法执行。
二:线程(threading)
线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
线程与进程的区别:
1 一个程序至少有一个进程,一个进程至少有一个线程.(进程可以理解成线程的容器) 2 进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。 3 线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和 程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。 4 进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调 度的一个独立单位. 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程 自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈)但是 它可与同属一个进程的其他的线程共享进程所拥有的全部资源. 一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.
三:线程的两种调用方式
直接调用:
import threading, time def sayhi(num): # 定义每个线程要运行的函数 print("running on number:%s" %num) time.sleep(3) if __name__ == "__main__": t1 = threading.Thread(target=sayhi,args=(1,)) # 生成一个线程实例 t2 = threading.Thread(target=sayhi,args=(2,)) # 生成一个线程实例 t1.start() # 启动线程 t2.start() print(t1.getName()) # 获取线程名 print(t2.getName()) #Thread-1 #Thread-2
继承式调用:
import threading, time class MyTread(threading.Thread): def __init__(self, num): threading.Thread.__init__(self) self.num = num def run(self): print("running on number: %s" %self.num) time.sleep(3) if __name__ == "__main__": t1 = MyTread(1) t2 = MyTread(2) t1.start() t2.start() print("ending......")
join&Daemon方法:
import threading from time import ctime,sleep import time def music(func): for i in range(2): print ("Begin listening to %s. %s" %(func,ctime())) sleep(4) print("end listening %s"%ctime()) def move(func): for i in range(2): print ("Begin watching at the %s! %s" %(func,ctime())) sleep(5) print('end watching %s'%ctime()) threads = [] t1 = threading.Thread(target=music,args=('七里香',)) threads.append(t1) t2 = threading.Thread(target=move,args=('阿甘正传',)) threads.append(t2) if __name__ == '__main__': for t in threads: # t.setDaemon(True) t.start() # t.join() # t1.join() t2.join()########考虑这三种join位置下的结果? print ("all over %s" %ctime())
setDaemon(True):
将线程声明为守护线程,必须在start() 方法调用之前设置, 如果不设置为守护线程程序会被无限挂起。这个方法基本和join是相反的。当我们 在程序运行中,执行一个主线程,如果主线程又创建一个子线程,主线程和子线程 就分兵两路,分别运行,那么当主线程完成想退出时,会检验子线程是否完成。如 果子线程未完成,则主线程会等待子线程完成后再退出。但是有时候我们需要的是 只要主线程完成了,不管子线程是否完成,都要和主线程一起退出,这时就可以 用setDaemon方法啦
join():
在子线程完成运行之前,这个子线程的父线程将一直被阻塞
四:同步锁:
#------同步锁----------- import threading import time def sub(): global num # num-=1 lock.acquire() temp=num time.sleep(0.01)#阻塞 num=temp-1 lock.release() num=100 l=[] lock=threading.Lock() for i in range(100): t=threading.Thread(target=sub) t.start() l.append(t) #所有的线程对象 for t in l: t.join() print(num)
五:递归锁:
########---递归锁---------------- import threading import time class MyThread(threading.Thread): def actionA(self): A.acquire() print(self.name,'gotA',time.ctime()) time.sleep(2) B.acquire() print(self.name, 'gotB', time.ctime()) time.sleep(1) B.release() A.release() def actionB(self): B.acquire() print(self.name, 'gotB', time.ctime()) time.sleep(2) A.acquire() print(self.name, 'gotA', time.ctime()) time.sleep(1) A.release() B.release() def run(self): self.actionA() # time.sleep(0.5) self.actionB() if __name__=='__main__': # A=threading.Lock() # B=threading.Lock() # r_lock=threading.RLock() L=[] for i in range(5): t=MyThread() t.start() L.append(t) for i in L: i.join() print('ending.....')
六:信号量
import threading,time class myThread(threading.Thread): def run(self): if semaphore.acquire(): print(self.name) time.sleep(5) semaphore.release() if __name__=="__main__": semaphore=threading.Semaphore(5) thrs=[] for i in range(100): thrs.append(myThread()) for t in thrs: t.start()
信号量用来控制线程并发数的,BoundedSemaphore或Semaphore管理一个内置的计数 器,每当调用acquire()时-1,调用release()时+1。
七:多线程利器queue
创建一个“队列”对象 import Queue q = Queue.Queue(maxsize = 10) Queue.Queue类即是一个队列的同步实现。队列长度可为无限或者有限。可通过Queue的构造函数的可选参数maxsize来设定队列长度。如果maxsize小于1就表示队列长度无限。 将一个值放入队列中 q.put(10) 调用队列对象的put()方法在队尾插入一个项目。put()有两个参数,第一个item为必需的,为插入项目的值;第二个block为可选参数,默认为 1。如果队列当前为空且block为1,put()方法就使调用线程暂停,直到空出一个数据单元。如果block为0,put方法将引发Full异常。 将一个值从队列中取出 q.get() 调用队列对象的get()方法从队头删除并返回一个项目。可选参数为block,默认为True。如果队列为空且block为True,get()就使调用线程暂停,直至有项目可用。如果队列为空且block为False,队列将引发Empty异常。 Python Queue模块有三种队列及构造函数: 1、Python Queue模块的FIFO队列先进先出。 class queue.Queue(maxsize) 2、LIFO类似于堆,即先进后出。 class queue.LifoQueue(maxsize) 3、还有一种是优先级队列级别越低越先出来。 class queue.PriorityQueue(maxsize) 此包中的常用方法(q = Queue.Queue()): q.qsize() 返回队列的大小 q.empty() 如果队列为空,返回True,反之False q.full() 如果队列满了,返回True,反之False q.full 与 maxsize 大小对应 q.get([block[, timeout]]) 获取队列,timeout等待时间 q.get_nowait() 相当q.get(False) 非阻塞 q.put(item) 写入队列,timeout等待时间 q.put_nowait(item) 相当q.put(item, False) q.task_done() 在完成一项工作之后,q.task_done() 函数向任务已经完成的队列发送一个信号 q.join() 实际上意味着等到队列为空,再执行别的操作
八:进程池 Pool
进程池内部维护一个进程序列。当使用时,则去进程池中获取一个进程,若进程池序列中没有可供使用的进程池,程序等待,直到进程池中可用进程为止。
- apply
- apply_async()
例子:
import queue import threading import time class ThreadPool(object): def __init__(self, max_num=20): self.queue = queue.Queue(max_num) for i in range(max_num): self.queue.put(threading.Thread) def get_thread(self): return self.queue.get() def add_thread(self): self.queue.put(threading.Thread) ''' pool = ThreadPool(10) def func(arg, p): print(arg) time.sleep(1) p.add_thread() for i in range(30): Pool = pool.get_thread() t = Pool(target=func, args=(i, pool)) t.start() '''