进程:

Python 解释器有一个全局解释器锁(PIL),导致每个 Python 进程中最多同时运行一个线程,因此 Python 多线程程序并不能改善程序性能,不能发挥多核系统的优势,可以通过这篇文章了解。

但是多进程程序不受此影响, Python 2.6 引入了 multiprocessing 来解决这个问题。这里介绍 multiprocessing 模块下的进程,进程同步,进程间通信和进程管理四个方面的内容。 这里主要讲解多进程的典型使用,multiprocessing 的 API 几乎是完复制了 threading 的API, 因此只需花少量的时间就可以熟悉 threading 编程了

由于GIL的存在,很多Python专家建议,多使用多进程,以便利用多核资源,而不是使用多线程。

下面来下一个简单生成线程的实例,如下:

import multiprocessing
import time def run(name):
time.sleep()
print("hello",name) if __name__ == "__main__":
for i in range():
p = multiprocessing.Process(target=run,args=("alex",))
p.start()
执行结果如下:
hello alex
hello alex
hello alex
hello alex
hello alex

上面一个程序就是多进程的实例,启动了5个进程,可见,多进程是multiprocessing模块;

multiprocessing.cpu_count()统计CPU的个数,即同时可以运行几个进程。cpu_count()统计CPU的个数,即几核CPU。

在Linux上,每一个进程都是由父进程启动的,根进程1,__init__()负责启动;父进程,每个进程必定有一个父进程。

下面我们来写一个程序,来看看进程里面的一些概念:

import multiprocessing,os,time

def info(title):
print(title)
print("Module name:",__name__)
print("parent processing:",os.getppid()) #获取线程父线程的PID
print("son processing:",os.getpid()) #获取线程的子线程PID
print("\n") def func(name):
info("\033[31m----------------函数func-------------------\033[0m") #启动线程之后调用info()函数
print("name:",name) if __name__ == "__main__":
info("\033[32m---------------主程序的进程信息-------------\033[0m")
'''启动一个进程'''
p = multiprocessing.Process(target=func,args=("geng",))
p.start()
执行结果:
---------------主程序的进程信息-------------
Module name: __main__
parent processing: 2601
son processing: 6877 ----------------函数func-------------------
Module name: __main__
parent processing: 6877
son processing: 6878 name: geng

上面程序中,__name__是指模块名,os.getppid()是获取父进程的ID,os.getpid()获取自己的进程PID,我们知道,进程都有自己的进程号,PID,

上面的进程PID:2601是父进程,启动了进程:6877,进程6877启动了6878,那么父进程2601是谁呢?这个进程是Pycharm的进程PID,程序的PID是由Pycharm进程启动的,在Linux上,每一个进程都是由父进程启动的。

    进程间通讯

不同进程间内存是不共享的,要想实现两个进程间的数据交换,可以用以下方法:

我们知道,线程之间数据是可以共享的,如下:

from multiprocessing import Process,Queue
import queue,threading def func(mess):
q.put(mess) if __name__ == "__main__":
q = queue.Queue()
'''定义一个线程'''
t = threading.Thread(target=func,args=("geng",))
t.start()
print(q.get())
执行结果:
geng

从上面看,线程之间是可以共享队列的数据的,下面我们来看下进程的情况:

from multiprocessing import Process
import queue,threading def func():
q.put(["alex","tom"]) if __name__ == "__main__":
q = queue.Queue()
'''定义一个线程'''
p = Process(target=func)
p.start()
print(q.get())
执行结果:
Traceback (most recent call last):
File "/home/zhuzhu/day10/进程数据共享.py", line , in <module>
print(q.get())
File "/usr/lib/python3.5/queue.py", line , in get
self.not_empty.wait()
File "/usr/lib/python3.5/threading.py", line , in wait
waiter.acquire()
KeyboardInterrupt

可见,进程之间是不能随便通信的,要想实现进程之间的通信,要使用进程Queue。如下:

from multiprocessing import Process,Queue

def func():
q.put(["alex","tom"]) if __name__ == "__main__":
q = Queue()
'''定义一个线程'''
p = Process(target=func)
p.start()
print(q.get())
执行结果:
['alex', 'tom']

可见,通过进程multiprocessing模块中间的进程Queue能够实现不同进程之间的通讯。进程之间的通信情况。

上面程序中,有两个进程,父进程和子进程,父进程是程序本身,是由Pycharm启动的,子进程p是由程序本身的父进程启动的,父进程就是程序本身。两者之间是相互独立的,想要实现数据的交流,要通过进程Queue。

    Pipe(管道):管道函数返回一个由管默认为双相连接的连接对象(双向)

通过管道之间实现数据的交换,管道有两头,连接两个线程,parent_conn,child_conn = Pipe(),就像socket一样,有客户端和服务器端,通过发送和接收数据,就能实现管道之间的数据交换,如parent_conn.send()和child_conn.recv(),并且管道之间可以接收和发送空的数据,都不会影响。如下:

'''线程之间正常是不能共享数据的,线程是相互独立的,要想共享数据,要通过一些特殊的方法,下面通过Pipe管道实现数据共享'''
'''Pipe实现数据共享是数据交换,与socket功能类似,一边发送数据,一边接收数据'''
from multiprocessing import Process,Pipe def func(mess):
child_conn.send(mess)
print("子进程发送的数据:",mess)
  child_conn.close() if __name__ == "__main__":
parent_conn,child_conn = Pipe() #建立管道,管道有两端,两个线程一边负责一端
while True:
mess = input("请输入您要交父线程的内容>>:")
p = Process(target=func,args=(mess,))
p.start()
p.join()
data = parent_conn.recv()
print("父进程接收到的消息:",data)
执行结果如下:
请输入您要交父线程的内容>>:子进程发送数据,父进程接收数据
子进程发送的数据: 子进程发送数据,父进程接收数据
父进程接收到的消息: 子进程发送数据,父进程接收数据
请输入您要交父线程的内容>>:管道有两端,通过两端管道的send,recv()实现数据的传输
子进程发送的数据: 管道有两端,通过两端管道的send,recv()实现数据的传输
父进程接收到的消息: 管道有两端,通过两端管道的send,recv()实现数据的传输
请输入您要交父线程的内容>>:管道可以收发空的消息
子进程发送的数据: 管道可以收发空的消息
父进程接收到的消息: 管道可以收发空的消息
请输入您要交父线程的内容>>:
子进程发送的数据:
父进程接收到的消息:
请输入您要交父线程的内容>>:上面通过收发空消息并没有报错。
子进程发送的数据: 上面通过收发空消息并没有报错。
父进程接收到的消息: 上面通过收发空消息并没有报错。

上面,我们通过管道,实现了两端数据的收发,Pipe(),有两端,parent_conn,child_conn = Pipe(),管道,当完成管道数据交换后,关闭管道,

当Pipe()管道关闭之后,就不能交换数据了。

管道Pipe()有两头,一边一个,两边负责收发各自的消息。

Pipe的源代码如下:

class Connection(object):
def send(self, obj):
pass def recv(self):
pass def fileno(self):
return def close(self):
pass def poll(self, timeout=None):
pass def send_bytes(self, buffer, offset=-, size=-):
pass def recv_bytes(self, maxlength=-):
pass def recv_bytes_into(self, buffer, offset=-):
pass def __enter__(self):
pass def __exit__(self, exc_type, exc_val, exc_tb):
pass def Pipe(duplex=True):
return Connection(), Connection()

Manager

进程之间相互独立,Manager默认自己会加锁,不用额外加锁,担心两个线程同时修改数据,这种事情不会发生,进程操作完了另外一个进程才会操作。

上面,我们通过Pipe()管道,Queue队列实现了线程之间的数据交换,但是也只是限于传递,各个线程之间是不能修改数据的,那么如何修改数据呢?我们可以通过多线程里面的Manager来修改线程之间的数据。如下:

"""之前都是共享数据,并不能在一个线程修改另外一个线程的数据,下面通过Manager来修改数据"""
from multiprocessing import Process,Manager
import os def func(d,l):
'''把Manger的生成的字典和列表实例当做参数传入,并修改'''
d[os.getpid()] = os.getppid()
l.append(os.getpid())
print("子线程的列表:",l) if __name__ == "__main__":
with Manager() as manager: #使用with定义
d = manager.dict() #生成一个字典,可在多个进程间共享和传递
l = manager.list() #定义一个Manager列表 p_lists = [] #定义一个线程空的字典,存放启动的线程,稍后遍历,确保都执行完毕
for k in range():
p = Process(target=func,args=(d,l))
p.start()
p_lists.append(p) for process in p_lists:
process.join() print("字典:",d)
print("列表:",l)
代码执行结果:
子线程的列表: [9717]
子线程的列表: [9717, 9720]
子线程的列表: [9717, 9720, 9718]
子线程的列表: [9717, 9720, 9718, 9722]
子线程的列表: [9717, 9720, 9718, 9722, 9727]
子线程的列表: [9717, 9720, 9718, 9722, 9727, 9725]
子线程的列表: [9717, 9720, 9718, 9722, 9727, 9725, 9733]
子线程的列表: [9717, 9720, 9718, 9722, 9727, 9725, 9733, 9734]
子线程的列表: [9717, 9720, 9718, 9722, 9727, 9725, 9733, 9734, 9731]
子线程的列表: [9717, 9720, 9718, 9722, 9727, 9725, 9733, 9734, 9731, 9736]
字典: {9736: 9708, 9734: 9708, 9731: 9708, 9717: 9708, 9718: 9708, 9720: 9708, 9722: 9708, 9733: 9708, 9725: 9708, 9727: 9708}

上面代码中,我们使用了Manager()来定义了字典和列表,通过Manager()定义的字典和列表是可以修改的,从结果可以看出,修改成功,但是所有主程序的代码都要在with Manager() as manager:后面,不然会报错。

如果不想注意缩进,即with Manager() as manager:所有语句缩进后面,可以通过赋值,manager = Manager()也可以,这样就能在同一个缩进里面执行程序,如下:

"""之前都是共享数据,并不能在一个线程修改另外一个线程的数据,下面通过Manager来修改数据"""
from multiprocessing import Process,Manager
import os def func(d,l):
'''把Manger的生成的字典和列表实例当做参数传入,并修改'''
d[os.getpid()] = os.getppid()
l.append(os.getpid())
print("子线程的列表:",l) if __name__ == "__main__":
manager = Manager() #使用with定义
d = manager.dict() #生成一个字典,可在多个进程间共享和传递
l = manager.list() #定义一个Manager列表 p_lists = [] #定义一个线程空的字典,存放启动的线程,稍后遍历,确保都执行完毕
for k in range():
p = Process(target=func,args=(d,l))
p.start()
p_lists.append(p) for process in p_lists:
process.join() print("字典:",d)
print("列表:",l)
执行结果如下:
子线程的列表: [10295]
子线程的列表: [10295, 10297]
子线程的列表: [10295, 10297, 10296, 10300, 10299]
子线程的列表: [10295, 10297, 10296, 10300, 10299]
子线程的列表: [10295, 10297, 10296, 10300, 10299]
子线程的列表: [10295, 10297, 10296, 10300, 10299, 10305, 10302]
子线程的列表: [10295, 10297, 10296, 10300, 10299, 10305, 10302]
子线程的列表: [10295, 10297, 10296, 10300, 10299, 10305, 10302, 10309, 10307]
子线程的列表: [10295, 10297, 10296, 10300, 10299, 10305, 10302, 10309, 10307, 10303]
子线程的列表: [10295, 10297, 10296, 10300, 10299, 10305, 10302, 10309, 10307, 10303]
字典: {10305: 10286, 10307: 10286, 10309: 10286, 10295: 10286, 10296: 10286, 10297: 10286, 10299: 10286, 10300: 10286, 10302: 10286, 10303: 10286}
列表: [10295, 10297, 10296, 10300, 10299, 10305, 10302, 10309, 10307, 10303]

上面使用的就是manager = Manager(),这样我们就不必过分担心缩进的问题了。

进程同步

如果不使用来自不同进程的锁输出,就很容易混淆起来。(Without using the lock output from the different processes is liable to get all mixed up.

进程之间是相互独立的,进程里面为什么需要锁呢?屏幕共享,锁存在的意义,由于屏幕共享,如果同时打印,就会出现错误,加锁的目的是只允许一个程序打印。

from multiprocessing import Process,Lock

'''进程是相互独立的,但是由于打印的时候屏幕是共享的,加锁的意义就是让一个进程打印的时候,其他进程暂时不打印,避免抢屏幕'''
def func(mess):
lock.acquire()
try:
print("\033[31m打印用户输入:%s\033[0m" %mess)
finally:
lock.release() #finally()不管是否有异常,都执行 if __name__ == "__main__":
lock = Lock()
mess = input("请输入您要让子线程打印的消息>>:")
for i in range():
p = Process(target=func,args=(mess,))
p.start()
执行结果:
请输入您要让子线程打印的消息>>:进程之间加锁的目的是防止屏幕打印错乱
打印用户输入:进程之间加锁的目的是防止屏幕打印错乱
打印用户输入:进程之间加锁的目的是防止屏幕打印错乱
打印用户输入:进程之间加锁的目的是防止屏幕打印错乱
打印用户输入:进程之间加锁的目的是防止屏幕打印错乱
打印用户输入:进程之间加锁的目的是防止屏幕打印错乱
打印用户输入:进程之间加锁的目的是防止屏幕打印错乱
打印用户输入:进程之间加锁的目的是防止屏幕打印错乱
打印用户输入:进程之间加锁的目的是防止屏幕打印错乱
打印用户输入:进程之间加锁的目的是防止屏幕打印错乱
打印用户输入:进程之间加锁的目的是防止屏幕打印错乱

上面程序就是加锁的情况,加锁是为了避免屏幕打印错乱,有时候多进程同时打印会出现打印错乱,由于屏幕共享,不知道其他线程什么时候执行完毕。

    进程池

进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。启一个进程等于克隆一个父进程,CPU开销非常大,在Windows启动100个进程都很慢。启一个进程就相当于克隆一个父进程的内存数据。

进程池中有两个方法:

1.apply          (串行)

2.apply_async    (asynchronous异步)

apply方法的定义:

def apply(self, func, args=(), kwds={}):
    '''
    Equivalent of `func(*args, **kwds)`.
    '''
    assert self._state == RUN
    return self.apply_async(func, args, kwds).get()

首先使用apply()方法,写一个串行的进程池,当然这种方法很少见,不怎么常用,如下:

from multiprocessing import Pool
import time,os
'''进程池,控制同一时间执行进程的个数,防止CPU运行吃力,启用进程很耗费CPU''' def fun():
print("\033[31min the process of %s\033[0m" %os.getpid())
time.sleep()
print("进程%s执行完毕" %os.getpid()) def bar():
'''当一个子线程执行完毕之后,父线程调用回调函数,比如公司发完工资之后,会发一条短信到你手机,这样就可以用回调函数'''
print("您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!") if __name__ == "__main__":
pool = Pool(processes=) #定义同一时间最大运行进程的个数
for i in range():
pool.apply(func=fun) print("The end!")
pool.close()
pool.join()
执行结果:
in the process of 13326
进程13326执行完毕
in the process of 13327
进程13327执行完毕
in the process of 13329
进程13329执行完毕
in the process of 13330
进程13330执行完毕
in the process of 13328
进程13328执行完毕
in the process of 13326
进程13326执行完毕
in the process of 13327
进程13327执行完毕
in the process of 13329
进程13329执行完毕
in the process of 13330
进程13330执行完毕
in the process of 13328
进程13328执行完毕
The end!

上面apply()是执行的串行进程,当一个进程执行完毕,才会执行另外一个,这样就失去了并发的意义,要想执行并发,就要使用apply_async并发执行。

    apply_async方法的定义:

def apply_async(self, func, args=(), kwds={}, callback=None,
  error_callback=None):
    '''
    Asynchronous version of `apply()` method.
    '''
    if self._state != RUN:
    raise ValueError("Pool not running")
    result = ApplyResult(self._cache, callback, error_callback)
    self._taskqueue.put(([(result._job, None, func, args, kwds)], None))
    return result

上面的程序是串行的,现在我们修改一下,让进程多并发执行(即异步),如下:

from multiprocessing import Pool
import time,os
'''进程池,控制同一时间执行进程的个数,防止CPU运行吃力,启用进程很耗费CPU''' def fun():
print("\033[32m-------------开始打印-------------------\033[0m")
print("\033[31min the process of %s\033[0m" %os.getpid())
time.sleep()
print("进程%s执行完毕" %os.getpid()) def bar():
'''当一个子线程执行完毕之后,父线程调用回调函数,比如公司发完工资之后,会发一条短信到你手机,这样就可以用回调函数'''
print("您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!") if __name__ == "__main__":
pool = Pool(processes=) #定义同一时间最大运行进程的个数
for i in range():
# pool.apply(func=fun)
pool.apply_async(func=fun) print("The end!")
pool.close()
pool.join()
执行结果如下:
The end!
-------------开始打印-------------------
in the process of 13562
-------------开始打印-------------------
in the process of 13563
-------------开始打印-------------------
in the process of 13564
-------------开始打印-------------------
-------------开始打印-------------------
in the process of 13565
in the process of 13566
进程13563执行完毕
进程13562执行完毕
进程13564执行完毕
进程13566执行完毕
进程13565执行完毕
-------------开始打印-------------------
in the process of 13563
-------------开始打印-------------------
in the process of 13566
-------------开始打印-------------------
in the process of 13564
-------------开始打印-------------------
in the process of 13565
-------------开始打印-------------------
in the process of 13562
进程13563执行完毕
进程13565执行完毕
进程13566执行完毕
进程13562执行完毕
进程13564执行完毕

可以看出,上面执行的结果是5个异步同时执行的,只有前5个进程执行完毕,才会继续执行,pool.apply_async()多并发异步执行,但是可以看出,上面打印是按照谁先执行就先打印到屏幕上的,有点错乱,当然这是多进程正常的情况,并且要注意,进程池中,是先pool.close()关闭进程池,然后join()的,这个跟断言有关,具体可以看源代码,但是一定要记住,必须有pool.join()不然会报错,打印不了,这个是个坑。

回调,我们经常会遇到这样的问题?就是做完一件事情之后,想备注一下,或者告知一下,比如,公司发完公司,总会通过银行发送一条消息到员工的手机上,如何操作呢?就可以用到进程池中的回调,如下:

callback=func(函数名),只需要在apply_async(func=函数名,args=(参数),callback=回调函数名)就能实现回调,如下,我们调用完线程之后,发送一条消息,如下:

from multiprocessing import Pool,Lock
import time,os
'''进程池,控制同一时间执行进程的个数,防止CPU运行吃力,启用进程很耗费CPU''' def fun():
print("\033[32m-------------开始打印-------------------\033[0m")
print("\033[31min the process of %s\033[0m" %os.getpid())
time.sleep()
print("进程%s执行完毕" %os.getpid()) def bar(arg):
'''当一个子线程执行完毕之后,父线程调用回调函数,比如公司发完工资之后,会发一条短信到你手机,这样就可以用回调函数'''
print("您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!") if __name__ == "__main__":
pool = Pool(processes=) #定义同一时间最大运行进程的个数
for i in range():
# pool.apply(func=fun)
pool.apply_async(func=fun,callback=bar) print("The end!")
pool.close()
pool.join()
执行如下:
-------------开始打印-------------------
in the process of 13778
-------------开始打印-------------------
in the process of 13779
-------------开始打印-------------------
in the process of 13780
进程13776执行完毕
进程13777执行完毕
进程13778执行完毕
进程13780执行完毕
进程13779执行完毕
您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!
-------------开始打印-------------------
in the process of 13776
您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!
-------------开始打印-------------------
in the process of 13779
您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!
-------------开始打印-------------------
in the process of 13778
您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!
-------------开始打印-------------------
in the process of 13777
您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!
-------------开始打印-------------------
in the process of 13780
进程13777执行完毕
进程13779执行完毕
您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!
您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!
进程13776执行完毕
进程13778执行完毕
您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!
进程13780执行完毕
您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!
您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!

上面程序中,我们给apply_async()里面的参数callback=bar,进行了赋值,让执行完前面的线程之后,由主线程调用回调函数,记住是主线程调用的回调函数,而不是子线程调用的。下面程序我们打印是谁调用的,就能验证这一说法:

from multiprocessing import Pool,Lock
import time,os
'''进程池,控制同一时间执行进程的个数,防止CPU运行吃力,启用进程很耗费CPU''' def fun():
print("\033[32m-------------开始打印-------------------\033[0m")
print("\033[31min the process of %s\033[0m" %os.getpid())
time.sleep()
print("进程%s执行完毕" %os.getpid())
print("子线程的PID:",os.getpid()) def bar(arg):
'''当一个子线程执行完毕之后,父线程调用回调函数,比如公司发完工资之后,会发一条短信到你手机,这样就可以用回调函数'''
print("您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!")
print("bar的线程PID:",os.getpid()) if __name__ == "__main__":
pool = Pool(processes=) #定义同一时间最大运行进程的个数
print("主线程的PID:",os.getpid())
for i in range():
# pool.apply(func=fun)
pool.apply_async(func=fun,callback=bar) print("The end!")
pool.close()
pool.join()

程序的执行结果如下:

主线程的PID:
The end!
-------------开始打印-------------------
in the process of
-------------开始打印-------------------
in the process of
-------------开始打印-------------------
in the process of
-------------开始打印-------------------
in the process of
-------------开始打印-------------------
in the process of
进程13868执行完毕
进程13867执行完毕
子线程的PID:
子线程的PID:
进程13870执行完毕
进程13871执行完毕
子线程的PID:
子线程的PID:
进程13869执行完毕
子线程的PID:
-------------开始打印-------------------
in the process of
您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!
bar的线程PID:
您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!
bar的线程PID:
-------------开始打印-------------------
in the process of
您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!
bar的线程PID:
-------------开始打印-------------------
in the process of
您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!
-------------开始打印-------------------
in the process of
bar的线程PID:
您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!
bar的线程PID:
-------------开始打印-------------------
in the process of
进程13868执行完毕
子线程的PID:
进程13871执行完毕
子线程的PID:
进程13869执行完毕
子线程的PID:
进程13867执行完毕
子线程的PID:
您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!
bar的线程PID:
您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!
bar的线程PID:
进程13870执行完毕
子线程的PID:
您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!
bar的线程PID:
您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!
bar的线程PID:
您好,您的工资已到账,请注意查收,如有疑问,请联系人事部,谢谢!!!
bar的线程PID:

从上面的bar函数的线程PID可以看出,bar的PID与主程序的PID是一样的,说明是主程序调用的回调函数,如果pool.close()关闭之后不join(),则程序会关闭,不管其他进程是否执行完毕。

操作完成数据库后,写一个日志,为什么不用子进程,子进程会连接N次,使用callback只需要主程序连接一次即可,提高效率。

join()    主进程阻塞,等待子进程的退出, join方法要在close或terminate之后使用

有两个值得提到的,一个是 callback,另外一个是 multiprocessing.pool.AsyncResult。 callback 是在结果返回之前,调用的一个函数,这个函数必须只有一个参数,它会首先接收到结果。callback 不能有耗时操作,因为它会阻塞主线程。

day10--进程的更多相关文章

  1. Python学习-day10 进程

    学习完线程,学习进程 进程和线程的语法有很多一样的地方,不过在操作系统中的差别确实很大. 模块是threading 和 multiprocessing 多进程multiprocessing multi ...

  2. Python Revisited Day10 (进程与线程)

    目录 10.1 使用多进程模块 10.2 将工作分布到多个线程 <Python 3 程序开发指南>学习笔记 有俩种方法可以对工作载荷进行分布,一种是使用多进程,另一种是使用多线程. 10. ...

  3. 多进程 multiprocessing 模块进程并发Process;Pool ;Queue队列 、threading模块;

    multiprocessing 模块中的 Process类提供了跨平台的多进程功能,在windows和linux系统都可以使用. 1.首先要实例化一个类,传入要执行的函数. 实例名 = Process ...

  4. 多进程、协程、事件驱动及select poll epoll

    目录 -多线程使用场景 -多进程 --简单的一个多进程例子 --进程间数据的交互实现方法 ---通过Queues和Pipe可以实现进程间数据的传递,但是不能实现数据的共享 ---Queues ---P ...

  5. 网络编程基础【day10】:我是一个进程(三)

    本节内容 1.引子 2.进程的诞生 3.线程 4.争吵 一.引子 我听说我的祖先们生活在专用计算机里, 一生只帮助人类做一件事情,比说微积分运算 了.人口统计了 .生成密码.甚至通过织布机印花 !   ...

  6. 网络编程基础【day10】:进程与线程介绍(一 )

    本节内容 1.概述 2.什么是进程? 3.什么是线程? 4.什么是携程? 5.存在的疑问 6.总结 一.概述 我们知道,所有的指令的操作都是有CPU来负责的,cpu是来负责运算的.OS(操作系统) 调 ...

  7. python_way day10 python和其他语言的作用域 、 python2.7多继承和3.5多继承的区别 、 socket 和 socketserver源码(支持并发处理socket,多进程,多线程)

    python_way day10 1.python的作用域和其他语言的作用域 2.python2.7多继承和3.5多继承的区别 3.socket和socketserver源码(并发处理socket) ...

  8. Python线程和协程-day10

    写在前面 上课第10天,打卡: 感谢Egon老师细致入微的讲解,的确有学到东西! 一.线程 1.关于线程的补充 线程:就是一条流水线的执行过程,一条流水线必须属于一个车间: 那这个车间的运行过程就是一 ...

  9. python开发学习-day10(select/poll/epoll回顾、redis、rabbitmq-pika)

    s12-20160319-day10 *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: ...

随机推荐

  1. Docker 入门 第三部分: 服务

    目录 Docker 入门 第三部分: 服务 先决条件 介绍 你的第一个 docker-compose.yml 文件 docker-compose.yml 运行你新建的负载均衡应用 扩展应用程序 卸载应 ...

  2. .Net进阶系列(10)-异步多线程综述(被替换)

    一. 综述 经过两个多个周的整理,异步多线程章节终于整理完成,如下图所示,主要从基本概念.委托的异步调用.Thread多线程.ThreadPool多线程.Task.Parallel并行计算.async ...

  3. springboot系列之-logging

    配置文件以application.yml为例说明: Spring Boot默认的日志组件为Logback. 一. 日志配置参数: logging: file: # 日志文件,绝对路径或相对路径 pat ...

  4. HTML5的manifest 本地离线缓存

    下面直接放测试代码: index.html <!DOCTYPE html> <html manifest="m.manifest"> <head> ...

  5. Linux 4.10.8 根文件系统制作(一)---环境搭建

    一.工具 制作工具为busybox 下载地址:https://busybox.net/ 解压: 二.制作文件系统 进入目录,执行make menuconfig: 2.1 busybox setting ...

  6. pyqt5 添加属性-类方法用属性形式访问

    方法一 装饰器法 import sys from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QHBoxLayout,QLab ...

  7. luogu P1486 [NOI2004]郁闷的出纳员

    一万年以后终于调过了这题 这道题主要是维护一个有序的集合(吧),所以使用平衡树(我这里用\(Splay\)) 记录一个变量\(ff\)(雾),表示所有工资的变化量 对于\(I\)操作,如果初始工资大于 ...

  8. 2017CCPC秦皇岛 E题String of CCPC&&ZOJ3985【模拟】

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3985 题意: 给定一个字符串,由c和p组成,可以添加c或者p. 串中出现一 ...

  9. [转]NOI_Linux Arbiter使用手册

    讲述清楚,简单易懂的Arbiter使用手册 转载自 https://www.cnblogs.com/gengchen/p/7761565.html Arbiter 系统使用说明 Overview Ar ...

  10. HashMap原理分析(JDK1.7.x之前)

    HashMap 实现Map.Cloneable.Serializable接口,继承AbstractMap基类. HashMap map = new HashMap<String,String&g ...