网络传输进阶篇----并发
Posted takafter
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络传输进阶篇----并发相关的知识,希望对你有一定的参考价值。
一、并发是什么
? 较为通俗的去理解并发这件事情本身,这就要牵扯到计算机的发展。我再这笼统的概括,在网上能够找到十分详细的计算机发展史。
? 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 Process
import os,time
def 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 running
19364 is running
18716 is running
19428 is done
18716 is done
19364 is done
?
?
第二次结果
28012 is running
7920 is running
23080 is running
7920 is done
28012 is done
23080 is done
? 互斥锁将解决这个问题。
? 互斥锁就是一个门卫,谁抢到谁先进去,剩下的人在下面等着。
? 虽然保证了质量,但是效率也就不存在了。互斥锁将本来的并发变成了串行。
from multiprocessing import Process,Lock
import os,time
def 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 Process
import 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/大佬
以上是关于网络传输进阶篇----并发的主要内容,如果未能解决你的问题,请参考以下文章