多线程的使用场景
IO操作不占用CPU
计算占用cpu
python多线程不适合cpu密集型操作的任务,适合IO操作密集型的任务
多进程
简单的一个多进程例子:(用于理解对多线程方法的使用)
和线程的方法类似,下面是一个简单的多进程代码
import time, multiprocessing
def run(name):
time.sleep(2)
print("hello", name)
if __name__ == "__main__":
for i in range(6):
p = multiprocessing.Process(target=run, args=("dean",))
p.start()
和之前学习的多线程结合在一起使用,代码如下:
import time,threading
import multiprocessing
def thread_run():
print(threading.get_ident()) #这里表示获取线程id
def run(name):
time.sleep(2)
print("hello", name)
t = threading.Thread(target=thread_run)
t.start()
if __name__ == "__main__":
for i in range(6):
p = multiprocessing.Process(target=run, args=("dean",))
p.start()
运行结果如下:
接着我们查看下面代码:
from multiprocessing import Process
import os
def info(title):
print(title)
print('module name:', __name__)
print('parent process:', os.getppid())
print('process id:', os.getpid())
print("\n\n")
def f(name):
info('\033[31;1mcalled from child process function f\033[0m')
print('hello', name)
if __name__ == '__main__':
info('\033[32;1mmain process line\033[0m')
运行结果如下:
我们这里可以看到父进程id:12204,并且会发现无论程序运行多少次都是这个,然后我们在windows任务管理器查看发现这个是pycharm的进程id.这里要记住:每一个子进程都是由父进程启动的
我们将上面代码中if __name__=”__main__”进行修改,如下:
if __name__ == '__main__':
info('\033[32;1mmain process line\033[0m')
p = Process(target=f, args=('bob',))
p.start()
运行结果如下:
进程间数据的交互,实现方法
通过Queues和Pipe可以实现进程间数据的传递,但是不能实现数据的共享
不同进程间内存不是共享的,要想实现两个进程间的数据交换,有以下方法:
Queues
使用方法和threading里的queue使用差不多
先回忆一下线程之间的数据共享,通过下面代码理解:
import threading
import queue
def func():
q.put([22,"dean",'hello'])
if __name__=="__main__":
q = queue.Queue()
t = threading.Thread(target=func)
t.start()
print(q.get(q))
运行结果:
从上述代码可以看出线程之间的数据是共享的:父线程可以访问子线程放入的数据,如果是多进程之间呢?将代码进行修改如下,让子进程调用父进程数据:
from multiprocessing import Process
import queue
def f():
q.put([11,None,"hello"])
if __name__=="__main__":
q = queue.Queue()
p = Process(target=f)
p.start()
print(q.get())
运行结果如下:
从这里我们也可以看出子进程是访问不到父进程的数据,我们再次将代码进行修改,写f方法的时候直接将q给线程传入,也就是,只有启动线程,就自动传入线程q,代码如下:
from multiprocessing import Process
import queue
def f(data):
data.put([11,None,"hello"])
if __name__=="__main__":
q = queue.Queue() #切记这里是线程q
p = Process(target=f,args=(q,))
p.start()
print(q.get())
运行结果如下:
这里我们需要知道:进程不能访问线程q,所以我们需要改成进程,代码如下:
from multiprocessing import Process,Queue
def f(data):
data.put([11,None,"hello"])
if __name__=="__main__":
q = Queue() #这里的q是进程q
p = Process(target=f,args=(q,))
p.start()
print(q.get())
运行结果:
这次我们就发现在父进程里就可以调用到子进程放入的数据
这里我们需要明白:这里的q其实是被克隆了一个q,然后将子线程序列化的内容传入的克隆q,然后再反序列化给q,从而实现了进程之间数据的传递
Pipe
实现代码例子:
from multiprocessing import Process,Pipe
def f(conn):
conn.send([22,None,"hello from child"])
conn.send([22,None,"hello from child2"])
print(conn.recv())
conn.close()
if __name__=="__main__":
left_conn,right_conn = Pipe()
p = Process(target=f,args=(right_conn,))
p.start()
print(left_conn.recv())
print(left_conn.recv