Re: py

楼主: sustainer123 (caster)   2024-09-25 15:23:33
※ 引述《sustainer123 (温水佳树的兄长大人)》之铭言:
: 进程(process)
: 进程是加载内存且将执行的程式
: 打开工作管理员
: 里面的东西就是进程
: 每个进程会被分配一个独立id(pid)
: 简单来讲 电脑执行一项任务就是一个进程
: 多进程(mutiprocessing)
: 假设我们需要同时完成多个任务
: 这时候可以使用多进程
: 多进程也就是说主进程外再建立子进程
: 并且把主进程的东西整份copy过去子进程
: unix中 python可以使用fork()建立子进程
: fork()会把主进程的东西复制到子进程
: 并回传pid到主进程与子进程
: 主进程会拿到子进程的pid
: 子进程会拿到0
: 假设子进程需要主进程的pid
: 可以使用get.ppid()
: windows并没有fork指令
: 我看文档 windows只能用spawn
: spawn与fork差别我没看很懂
: 大致上就fork比较快但比较不安全
: spawn比较慢但比较安全
: 反正windows也用不到spawn以外两种 先这样:)))
: 有兴趣可以看下面网站
: 总之 我们使用multiprocessing
: 我直接copy py文档的code:
: 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())
: def f(name):
: info('function f')
: print('hello', name)
: if __name__ == '__main__':
: info('main line')
: p = Process(target=f, args=('bob',))
: p.start()
: p.join()
: 输出:
: main line
: module name: __main__
: parent process: 1280
: process id: 24780
: function f
: module name: __mp_main__
: parent process: 24780
: process id: 3672
: hello bob
: 首先 程式执行主进程
: 之后程式执行子进程
: 这边使用process这个类完成任务
: target是目标函数 args是传入目标函数的参数
: p.start()是启动子进程
: p.join()是等待子进程结束才会往下运行
: 假设一次要设置多个进程
: 我们可以使用pool 一样使用文档code:
: from multiprocessing import Pool
: def f(x):
: return x*x
: if __name__ == '__main__':
: with Pool(5) as p:
: print(p.map(f, [1, 2, 3,4,5,6]))
: 这边我有修改一下 我在list里面多加几个元素
: 这程式是pool池开五个进程
: 然后子进程去处理下面的程式
: 我们这边只开五个进程 但里面有6个元素
: 所以6必须等到有个进程被释出 此元素才会被处理
: 一般来说 pool开的大小 == cpu核数
: 等等再写进程间沟通跟锁 先这样
: 参考资料:
: https://stackoverflow.com/questions/64095876/multiprocessing-fork-vs-spawn
: https://docs.python.org/zh-cn/3.12/library/multiprocessing.html
接着讲进程间构通
multiprocessing提供两种方法queue与pipe
doc:
from multiprocessing import Process, Queue
def f(q):
q.put([42, None, 'hello'])
if __name__ == '__main__':
q = Queue()
p = Process(target=f, args=(q,))
p.start()
print(q.get()) # 打印 "[42, None, 'hello']"
p.join()
首先创queue 之后创建子进程执行函数f 参数为queue
开始执行子进程 主进程打印q里面的东西
这边q.get()会等到queue里面有东西为止
最后确认子进程结束才继续父进程
pipe doc:
from multiprocessing import Process, Pipe
def f(conn):
conn.send([42, None, 'hello'])
conn.close()
if __name__ == '__main__':
parent_conn, child_conn = Pipe()
p = Process(target=f, args=(child_conn,))
p.start()
print(parent_conn.recv()) # 打印 "[42, None, 'hello']"
p.join()
程式码大同小异
queue跟pipe的差别在于:
假设有两个进程或线程(thread)同时读或同时写会出问题
但queue没差
使用场景可能就pipe适合只有两个进程的沟通 queue随便你用
再谈一下锁
有些情况下 我们会希望执行完成进程1再执行进程2
这就需要用上锁
doc:
from multiprocessing import Process, Lock
def f(l, i):
l.acquire()
try:
print('hello world', i)
finally:
l.release()
if __name__ == '__main__':
lock = Lock()
for num in range(10):
Process(target=f, args=(lock, num)).start()
l.acquire()是获取锁
假设锁被其他进程拿走
这边就会卡著
l.release()
释放锁 没这个会整个程式卡死 一定要写
锁大致上就长这样
我稍微改写一下上面的code 假设没锁的情况:
from multiprocessing import Process
def f(i):
print('hello world', i)
if __name__ == '__main__':
for num in range(10):
p = Process(target=f, args=(num,))
p.start()
输出:
hello world 1
hello world 0
hello world 2
hello world 3
hello world 4
hello world 5
hello world 6
hello world 7
hello world 8
hello world 9
假如没有锁 顺序可能就会乱掉
多进程大抵这样
使用场合就cpu密集任务ㄅ
不过要搞cpu密集任务 py这性能 还不如用别的语言写
老实说 我实战也还没用过多进程
作者: JerryChungYC (JerryChung)   2024-09-25 15:31:00
什么叫同时打印
楼主: sustainer123 (caster)   2024-09-25 15:34:00
就正常情况下 会是一排helloworld0-9我是期待会出现 helloworld1helloworld2并排的输出或者交错的情况 我是想举例没锁会发生什么事不过没写好 可能要再改一下或用别的例子
作者: JerryChungYC (JerryChung)   2024-09-25 15:43:00
可是print不是内建一个换行符吗 不会有并排发生吧
楼主: sustainer123 (caster)   2024-09-25 15:46:00
对欸 没想清楚 这边我再想一下怎么改

Links booklink

Contact Us: admin [ a t ] ucptt.com