一、并发是什么
? 较为通俗的去理解并发这件事情本身,这就要牵扯到计算机的发展。我再这笼统的概括,在网上能够找到十分详细的计算机发展史。
? https://blog.csdn.net/zzwu/article/details/77792789——请参见大佬的文章
? 在计算及一开始,工业生产能力并不能实现如今的多核的生产条件,当然也包括 那个时候并没有相关的理论。所以,在那个时候运行计算机那是相当的麻烦,很多人只能排着队等着来。这时候,优秀的程序猿就思考着为什么不能在计算机计算他人的内容的时候,接着运行别人的呢。因此他们就想到了并发——同时运行多个程序在一个处理器上。因为当程序在运行的时候,除开一些较为复杂的计算下,处理器占用较为多之外,很多时候都是进行的文件的读写 也就是 I/O 功能,这只占用计算机处理器的一小部分,大多数的部分就只能白白浪费。毕竟,效率就是生产力啊!!
? 引用百度的正规称呼——“并发,在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。”——应用自百度
二、进程——基本内容
1.什么是进程
? 正在进行的一个过程或者说一个任务。
2.进程和程序
? 程序是一对代码,进程则是程序的运行过程。
3.并发和并行
? 并发是看起来是同时进行了,但实际是处理器在多个任务之间的高速来回移动。
? 并行是真正的同时运行,但条件是得有多个CPU。因为一个CPU只能执行一个任务。
?
三、进程——multiprocessing模块
1.Process类
? **创建进程**
?
Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化得到的对象,可用来开启一个子进程?强调:1. 需要使用关键字的方式来指定参数2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号
? **参数介绍**
group参数未使用,值始终为None?target表示调用对象,即子进程要执行的任务?args表示调用对象的位置参数元组,args=(1,2,‘egon‘,)?kwargs表示调用对象的字典,kwargs={‘name‘:‘egon‘,‘age‘:18}?name为子进程的名称
? **方法介绍**
p.start():启动进程,并调用该子进程中的p.run() p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法 ?p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁p.is_alive():如果p仍然运行,返回True?p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间。
? **属性介绍**
p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置?p.name:进程的名称?p.pid:进程的pid
2.Process类的使用
? **windows的Process必须在 if name == ‘main‘:下**
?
? **创建方式一**
#!/usr/bin/python# -*- coding:utf-8 -*-from multiprocessing import Process??def people(name, sex): print("%s is %s" % (name, sex))??if __name__ == ‘__main__‘: p1 = Process(target=people, args=("张三", "man",)) p2 = Process(target=people, args=("李四", "man",)) p3 = Process(target=people, args=("狗蛋", "female",))? p1.start() p2.start() p3.start()? print("主要程序")
? **方式二**
#!/usr/bin/python# -*- coding:utf-8 -*-from multiprocessing import Process??class People(Process): def __init__(self, name, sex): super().__init__() self.name = name self.sex = sex? def run(self): print("%s is %s" % (self.name, self.sex))??if __name__ == ‘__main__‘: p1 = People("张三", "man") p2 = People("李四", "man") p3 = People("狗蛋", "female")? p1.start() p2.start() p3.start()? print("主要程序")
3.joint
? 通过上面的创建,能发现的一个问题就是:在主进程都已经结束完成后,子进程并没有完成。因为我们看到的代码只是向处理器发出了一个信号,但是实际上并没有运行。而主进程并不需要进行进程方面的创建,直接就运行了。
? 那么,主进程能够等着子进程运行完成之后,自己再进行吗?
? 答案显然是可以的。
? 只需要在主进程之前加上joint()就可以。
? joint就是认为的对主程序进行阻塞,只有joint所对应的子进程运行完成后,主进程才能运行。
#!/usr/bin/python# -*- coding:utf-8 -*-from multiprocessing import Process??def people(name, sex): print("%s is %s" % (name, sex))??if __name__ == ‘__main__‘: p1 = Process(target=people, args=("张三", "man",)) p2 = Process(target=people, args=("李四", "man",)) p3 = Process(target=people, args=("狗蛋", "female",))? p1.start() p2.start() p3.start()? p1.join() p2.join() p3.join()? print("主要程序") #注意:有多少个对象,就要有对应的join
? **注意:加上joint的进程并不是串行**
? 因为joint阻塞了主进程,但是子进程还是并发的在进行着。和串行一个一个运行还是有着本质的不用的。
? **对象其他属性或方法**
? **terminal 与 is——alive**
#!/usr/bin/python# -*- coding:utf-8 -*-from multiprocessing import Process??def people(name, sex): print("%s is %s" % (name, sex))??if __name__ == ‘__main__‘: p1 = Process(target=people, args=("张三", "man",)) p1.start() p1.terminate() print(p1.is_alive()) print("主要程序")
运行后的结果:
True主要程序
? **name 与 pid**
?
#!/usr/bin/python# -*- coding:utf-8 -*-from multiprocessing import Process??def people(name, sex): print("%s is %s" % (name, sex))??if __name__ == ‘__main__‘: p1 = Process(target=people, args=("张三", "man",)) p1.start()? print(p1.name, p1.pid)? print("主要程序")
运行结果:
Process-1 17072主要程序张三 is man
4.守护进程
? 守护进程就是伴随主进程左右的子进程,在主进程结束之前,自己绝对不会结束的子进程。
? **强调:一、主进程结束就终止;二、守护进程内不能开子进程,否则抛出异常**
?
#!/usr/bin/python# -*- coding:utf-8 -*-from multiprocessing import Process??def people(name, sex): print("%s is %s" % (name, sex))??if __name__ == ‘__main__‘: p1 = Process(target=people, args=("张三", "man",))? p1.daemon = True p1.start()? print("主进程")?# daemon必须要在start上面
5.互斥锁
? 并发虽然解决了效率的问题,但是也带来了一个问题就是容易带来错乱。
from multiprocessing import Processimport os,timedef work(): print(‘%s is running‘ %os.getpid()) time.sleep(2) print(‘%s is done‘ %os.getpid())?if __name__ == ‘__main__‘: for i in range(3): p=Process(target=work) p.start()
运行结果:
第一次结果19428 is running19364 is running18716 is running19428 is done18716 is done19364 is done??第二次结果28012 is running7920 is running23080 is running7920 is done28012 is done23080 is done
? 互斥锁将解决这个问题。
? 互斥锁就是一个门卫,谁抢到谁先进去,剩下的人在下面等着。
? 虽然保证了质量,但是效率也就不存在了。互斥锁将本来的并发变成了串行。
from multiprocessing import Process,Lockimport os,timedef work(lock): lock.acquire() #加锁 print(‘%s is running‘ %os.getpid()) time.sleep(2) print(‘%s is done‘ %os.getpid()) lock.release() #释放锁if __name__ == ‘__main__‘: lock=Lock() for i in range(3): p=Process(target=work,args=(lock,)) p.start() #加上锁acquire之后一定要在最后release 否则下面的数据根本进不去
? **互斥锁与joint**
? joint是一个一个的运行,即上一个结束,下一个进去
? 互斥锁是多个一起去抢,谁抢到谁运行。然后再抢,在运行。如此循环往复。
? 即,join是将一个任务整体串行,而互斥锁的好处则是可以将一个任务中的某一段代码串行,比如只让task函数中的get任务串行
def task(name,): search(name) # 并发执行? lock.acquire() get(name) #串行执行 lock.release()
? 互斥锁中可以有部分是并发执行,而joint无法做到
6.队列
? **重要**
#队列的创建Queue([maxsize]):创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递。 #!/usr/bin/python# -*- coding:utf-8 -*-from multiprocessing import Processimport queue??def people(name, sex): print("%s is %s" % (name, sex))??if __name__ == ‘__main__‘: p1 = Process(target=people, args=("张三", "man",)) p2 = Process(target=people, args=("李四", "man",)) p3 = Process(target=people, args=("狗蛋", "female",))? q = queue.Queue(2) q.put(p1) q.put(p2) print(q.full())? p1.start() p2.start() p3.start() print(q.get()) print(q.get())? print(q.empty())? print("主要程序") #如果q.put()和 q.get()查过2 程序会卡住不再运行
本文知识点引自与http://www.cnblogs.com/linhaifeng/大佬
原文地址:https://www.cnblogs.com/takafter/p/9385924.html