程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程。
程序和进程的区别就在于:程序是指令的集合,它是进程运行的静态描述文本;进程是程序的一次执行活动,属于动态概念。
简单点说就是:进程就是一个程序在一个数据集上的一次动态执行过程。
一个时间点只能做一件事,不能同时干两件及以上的事;
在执行的过程进程如果阻塞,例如等待输入,整个进程就会挂起,即使进程中有些工作不依赖于输入的数据,也将无法执行。
线程也叫轻量级进程,它是一个基本的CPU执行单元,也是程序执行过程中的最小单元;
一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务;
突破一个进程只能干一样事的缺陷,使到进程内并发成为可能;
线程的引入减小了程序并发执行时的开销,提高了操作系统的并发性能;
线程是执行的指令集 , 进程是资源的集合
线程的启动速度要比进程的启动速度要快
两个线程的执行速度是一样的,进程与线程的运行速度是没有可比性的
线程共享创建它的进程的内存空间 , 进程的内存是独立的
两个线程共享的数据都是同一份数据 , 两个子进程的数据不是共享的 , 而且数据是独立的
同一个进程的线程之间可以直接交流 , 同一个主进程的多个子进程之间是不可以进行交流 , 如果两个进程之间需要通信 , 就必须要通过一个中间代理来实现
一个新的线程很容易被创建 , 一个新的进程创建需要对父进程进行一次克隆
一个线程可以控制和操作同一个进程里的其他线程 , 线程与线程之间没有隶属关系 , 但是进程只能操作子进程
改变主线程 , 有可能会影响到其他线程的行为 , 但是对于父进程的修改是不会影响子进程
直接调用:
import threading import time def run(n): #定义线程要运行的函数 print('task',n) time.sleep(2) if __name__ == '__main__': t1 = threading.Thread(target=run,args=(1,)) #生成一个线程 t2 = threading.Thread(target=run,args=(2,)) #生成一个另外线程 t1.start() # 启动线程 t2.start() # 启动另外一个线程 print(t1.getName()) # 获取线程名 print(t2.getName()) print('I am main thread') #主线程 #这个进程里面有三个线程,1个主线程,t1,t2两个子线程 #子线程和主线程是同步开启的,主线程结束后,要等子线程全部结束后,进程才会关闭PS:线程相关的方法:
start 线程准备就绪,等待CPU调度 setName 为线程设置名称 getName 获取线程名称 run 线程被cpu调度后自动执行线程对象的run方法 # 下面会讲到 setDaemon 将线程声明为守护线程,必须在start() 方法调用之前设setDaemon(),只要主线程完成了,不管子线程是否完成,都要和主线程一起退出 join 逐个执行每个线程,执行完毕后继续往下执行,该方法保证当前线程执行完成后再执行其它线程,使得多线程变得无意义。继承式调用:
import threading import time class MyThread(threading.Thread): #继承threading,Thread模块 def __init__(self,n): threading.Thread.__init__() #继承父类 # 或者super(MyThread, self).__init__() self.n = n def run(self): #定义每个线程要运行的函数,必须用run print('task',self.n) time.sleep(2) if __name__ == '__main__': t1 = MyThread(1) t2 = MyThread(2) t1.start() t2.start() print('I am main thread')主线程:当一个程序启动时 , 就有一个进程被操作系统创建 , 与此同时一个线程也立刻运行 , 该线程通常叫做程序的主线程;
子线程 : 因为程序是开始时就执行的 , 如果你需要再创建线程 , 那么创建的线程就是这个主线程的子线程;
join应用:
import threading import time def run(n): print("task ",n ) time.sleep(2) start_time = time.time() t_objs = [] # 存线程实例 for i in range(10): #生成10个线程 t = threading.Thread(target=run,args=("t-%s" %i ,)) t.start() t_objs.append(t) #为了不阻塞后面线程的启动,不在这里join,先放到一个列表里 for t in t_objs: #循环线程实例列表,等待所有线程执行完毕 t.join() print("---all threads has finished...") print("cost:",time.time() - start_time)setDaemon应用:
import threading import time def run(n): print('task',n) time.sleep(2) print('i am 子线程') #主线程结束,setDaemon不管有没有运行完都会被销毁 if __name__ == '__main__': t1 = threading.Thread(target=run,args=(1,)) t2 = threading.Thread(target=run,args=(2,)) t1.setDaemon(True) #设置守护线程,放在start之前 t1.start() t2.setDaemon(True) t2.start() print('I am main thread') 结果: task 1 task 2 I am main threadlock:如果有多个进程对同一文件进行修改 , 就会造成错乱 , 所以我们为了保护文件数据的安全 , 就需要给其进行加锁,join为整体串行 , lock为局部串行
Rlock(递归锁):在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁,因为系统判断这部分资源都正在使用,所有这两个线程在无外力作用下将一直等待下去。就是解决死锁的问题
加锁:
import time import threading def addNum(): global num #在每个线程中都获取这个全局变量 print('--get num:',num ) time.sleep(1) lock.acquire() #修改数据前加锁 num -=1 #对此公共变量进行-1操作 lock.release() #修改后释放 num = 100 #设定一个共享变量 thread_list = [] lock = threading.Lock() #生成全局锁 for i in range(100): t = threading.Thread(target=addNum) t.start() thread_list.append(t) for t in thread_list: #等待所有线程执行完毕 t.join() print('final num:', num )互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如食堂打饭有5个窗口,那最多只允许5个人同时打饭,后面的人只能等里面有人打完才能去打。
import threading, time def run(n): semaphore.acquire() time.sleep(1) print("run the thread: %s\n" % n) semaphore.release() if __name__ == '__main__': semaphore = threading.BoundedSemaphore(5) # 最多允许5个线程同时运行 for i in range(20): t = threading.Thread(target=run, args=(i,)) t.start() while threading.active_count() != 1: pass else: print('----all threads done---') semaphoreQueue是python标准库中的线程安全的队列(FIFO)实现,提供了一个适用于多线程编程的先进先出的数据结构,即队列,用来在生产者和消费者线程之间的信息传递
FIFO即First in First Out,先进先出。Queue提供了一个基本的FIFO容器,使用方法很简单,maxsize是个整数,指明了队列中能存放的数据个数的上限。一旦达到上限,插入会导致阻塞,直到队列中的数据被消费掉。如果maxsize小于或者等于0,队列大小没有限制。
简单的FIFO:
import Queue q = Queue.Queue() for i in range(5): q.put(i) while not q.empty(): print q.get() 0 1 2 3 4 结果LIFO即Last in First Out,后进先出。与栈的类似;
简单的LIFO:
import Queue q = Queue.LifoQueue() for i in range(5): q.put(i) while not q.empty(): print q.get() 4 3 2 1 0 结果python线程的事件用于主线程控制其他线程的执行,事件主要提供了三个方法 set、wait、clear。
事件处理的机制:全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,那么event.wait 方法时便不再阻塞。
# -*- coding:utf-8 -*- # @Author : Clint import threading def do(event): print('start') event.wait() print('execute') event_obj = threading.Event() for i in range(10): t = threading.Thread(target=do, args=(event_obj,)) t.start() event_obj.clear() inp = input('input:') if inp == 'true': event_obj.set()使得线程等待,只有满足某条件时,才释放n个线程
def condition_func(): ret = False inp = input('>>>') if inp == '1': ret = True return ret def run(n): con.acquire() con.wait_for(condition_func) print("run the thread: %s" %n) con.release() if __name__ == '__main__': con = threading.Condition() for i in range(10): t = threading.Thread(target=run, args=(i,)) t.start()进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。
进程池中有两个方法:apply、apply_async
# -*- coding:utf-8 -*- # @Author : Clint from multiprocessing import Process, Pool import time def Foo(i): time.sleep(2) return i + 100 def Bar(arg): print(arg) pool = Pool(5) # print pool.apply(Foo,(1,)) # print pool.apply_async(func =Foo, args=(1,)).get() for i in range(10): pool.apply_async(func=Foo, args=(i,), callback=Bar) print('end') pool.close() pool.join() # 进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。转载于:https://www.cnblogs.com/Utopia-Clint/p/10885551.html