进程概念:进程,是计算机中的程序关于某数据集合上的一次运动活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。即执行中的程序是进程,例如qq不是进程,当qq运行的时候,就是一个进程
线程概念:线程,有时被称为轻量级进程,是程序执行流的最小单元。可以理解为,线程是属于进程的,平时写的简单程序是单线程的,多线程和多线程的区别在于多线程可以同时处理多个任务。
进程之间的内存独立,而属于同一个进程多个线程之间的内存是共享的,多个线程可以直接对他们所在进程的内存数据进行读写并在线程间进行交换。
协程概念:协程是一种用户态的轻量级线程,如果说多进程对于多cpu,多线程对于多核cpu,那么事件驱动和协程则是在充分挖掘不断提高性能的单核cpu的潜力,既可以利用异步优势,又可以避免反复系统调用,还有进程切换造成的开销。协程也是单线程,但是它能让原来要使用异步+回调方式写的代码,可以用看似同步的方式写出来,他是实现推拉互动的所谓非抢占式协作的关键。对于python来说,由于python多线程中解释器导致的同时只能有一个线程访问cpu,所以对协程需求就相比其他语言更为紧迫。
多进程:多个任务,比如音乐,word等
多线程:在进程内部做多件事,即多个子任务,比如word里的打字、打印等同时进行
多任务实现的3种方式:
多进程模式
多线程模式
多进程+多线程模式
线程是最小的执行单元,进程由至少一个线程组成
拥有一个多进程程序:
import multiprocessing #引入multiprocessing模块
import time
def func(msg): #要放在子进程执行的代码
for i in range(s):
print(msg)
time.sleep(3)
if __name__ == '__main__':
p = multiprocessing.Process(target = func,args = ('hello',))#创建一个新进程,将要放在子进程中执行的方法名和参数传给multiprocessing类
p.start() #启动子进程
p.join() #设置主进程阻塞,知道子进程执行完毕在继续完成
print('have done')
#注意:必须在启动子进程前加上if__name__ == 'main'
进程池:
def func(msg):
print(msg,'*** in func')
time.sleep(3)
if __name__ == '__main__':
pool = multiprocessing.Pool(processes = 5)#初始化一个进程池,参数是5,表示这个进程池中将有5个进程
for i in range(3):
print(i)
pool.apply_async(func,('hello %d'%(i), ))#为进程池中的进程注入func方法,这里有apply_async和apply两种方式,分别表示‘同步’和'异步'
#pool.apply(func,('hello %d'%(i), ))
pool.close() #关闭进程池,至此,进程池不再有进程可以接受任务
#pool.terminate() #结束工作进程,即结束当前进程池中的所有进程,不再处理未完成的任务
pool.join()#主进程阻塞,等待子进程执行完毕,再继续执行主进程,等待子进程的退出,join方法要在close或terminame之后使用
print('have dong')
#teminame和join是一对方法,表示的内容截然相反,两个方法都必须在close方法之后执行,当然也可以不执行这两个方法,那么子进程和主进程就各自执行各自的,无论执行到那里,子进程会随着主进程的结束而结束
获取进程池中进程的执行结果
import multiprocessing
import time
def func(msg):
print('msg:',msg)
time.sleep(3)
print('end')
return('multi_result:'+msg)
if __name__ == '__main__':
pool = multiprocessing.Pool(processes = 4)
result = []
for i in xrange(3):
msg = 'hello %d'%(i)
multi_result = pool.apply_async(func,(msg, ))
result.append(multi_result)
pool.close()
pool.join()
for res in result:
print(res.get())
print('have done')
进程之间的内存共享
每个进程都拥有自己的内存空间,进程间的内存是无法共享的
但是python提供了方法让程序的子进程之间实现简单的数据共享,一个是Array数组,一个是multiprocessing模块中的Manager类,需要注意的是,Array数组大小必须固定,Manager需要在linux系统下运行
from multiprocessing import Process,Array
temp = Array('i',[11,22,33,44])
def Foo(i):
temp[i] = 100+i
for item in temp:
print(i,'---------->',item)
for i in range(2):
p = Precess(target = Foo,args = (i,))
p.start
多进程
unix/linux操作系统提供了一个fork()系统调用,它非常特殊,普通函数的调用,调用一次返回一次,但是fork()调用一次,返回两次,因为操作系统自动把当前进程(父进程)复制了一份(子进程),然后,分别在父进程和子进程内返回
子进程永远返回0,而父进程返回子进程的ID,这样做的理由是,一个父进程可以fork出很多子进程,所以,父进程要记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程的ID
python的os模块封装了常见系统调用,其中就包括fork,可以在python程序中创建子进程
import os
print('Process (%s) start...'%os.getpid())
#only works on unix/linux/mac
pid = os.fork() #使用os.fork()之后,在内存中把进程的代码及内存分配情况拷贝一份生成子程序的运行空间,这样子进程的所有代码都与父进程一样,两个进程之间的运行是独立的,互不影响
if pid == 0:#在父进程中获取到的pid号是子进程的pid号,在子进程中获取的pid是0
print('I an child process (%s) and my parent is %s'%(os.getpid(),os.getppid()))
else:
print('I (%s) just created a child process (%s)'%(os.getpid(),pid))
Process (876) start... I (876) just created a child process (877). I am child process (877) and my parent is 876.