多进程开发

进程是计算机资源分配的最小单位;一个进程可以有多个线程,同一个进程中线程共享资源

进程和进程之间是相互隔离的

Python中通过多进程可以利用CPU多核,使用于计算密集型操作

1.1进程

import multiprocessing

def task(agr):
    pass

def run():
    p=multiprocessing.Process(target=task,args=('123',))
    p.start()

if __name__=="__main__":
    run()

要求:启动代码要放在if name=="main": 下

multiprocessing创建进程的方式
fork 【几乎开拷贝所有的父进程资源】【支持文件对象/线程锁传参】【unix】【任意位置开始】【快】
spawn【run参数传必备资源】【不支持文件对象/线程锁传参】【unix,win】【main代码块开始】【慢慢】
fokserver【run参数传必备资源】【不支持文件对象/线程锁传参】【部分unix】【main代码块开始】
import multiprocessing
import threading
import time


def func():
    with lock:
        print(666)
        time.sleep(1)

def task():
	#子进程 copy父进程资源,包括进程锁
    print(111)
    for i in range(10):
        t=threading.Thread(target=func)
        t.start()
    time.sleep(10)
    #子进程的主线程被锁,在锁释放前无法切换线程
    lock.release()


if __name__=="__main__":
    multiprocessing.set_start_method("fork")
    name=[]
    lock = threading.RLock()##加锁
    lock.acquire()
    p=multiprocessing.Process(target=task)
    p.start()

锁是Python提供给我们能够自行操控线程切换的一种手段,使用锁可以让线程的切换变的有序。

1.2常见功能

进程的常见方法:

  • p.start():当前进程准备就绪,等待被cpu调度(工作单元就是进程中的线程)

  • p.jion():等待当前进程的任务执行完毕后再向下继续执行

import multiprocessing
import  time
from  multiprocessing import Process

def task():
    time.sleep(10)
    print('执行中。。。。。。。')

if __name__=="__main__":
    multiprocessing.set_start_method('spawn')
    p=Process(target=task)
    p.start()
    p.join()

    print("执行完毕")
  • p.daemon=布尔值,守护进程(必须放在start之前)

  • p.daemon=Ture,设置为守护进程,主进程结束子进程

  • p.daemon=False,设置为非守护进程,主进程等待子进程

import multiprocessing
import  time
from  multiprocessing import Process

def task():
    time.sleep(10)
    print('执行中。。。。。。。')

if __name__=="__main__":
    multiprocessing.set_start_method('spawn')
    p=Process(target=task)
    p.daemon=False
    p.start()
    # p.join()

    print("执行完毕")
  • 进程名字的设置与获取

  • 设置:p.name='创建的子进程1'

  • 获取:multiprocessing.current_process().name

  • 获取当前进程id:os.getpid()

  • 获取父进程id:os.getppid()

  • 获取当前进程的线程:threading.enumerate()

import multiprocessing
import  time
from  multiprocessing import Process
import threading

def func():
    time.sleep(3)

def task():
    for i in range(10):
        t=threading.Thread(target=func)
        t.start()
    time.sleep(1)
    print('线程个数',len(threading.enumerate()))
    print('当前进程的名字',multiprocessing.current_process().name)

if __name__=="__main__":
    multiprocessing.set_start_method('spawn')
    p=Process(target=task)
    p.name='创建的子进程1'
    p.start()
    print("执行完毕")
  • 自定义进程类,直接将子进程的任务写都run方法中

import multiprocessing
import  time
from  multiprocessing import Process
import os
class MyPorcess(Process):
    def run(self):
        print('进程',self._args,os.getpid())

if __name__=="__main__":
    print(os.getpid())
    multiprocessing.set_start_method("spawn")
    p=MyPorcess(args=('123',))
    p.start()
    print('end')
  • 获取cpu个数,程序一般创建多少个进程(利用cpu的多核优势)

import multiprocessing
multiprocessing.cpu_count()

2.进程间的数据共享

进程是资源分配的最小单元,每个进程间都维护自己独立的数据,不共享

import multiprocessing


def task(data):
    data.append(324)


if __name__ == "__main__":
    data_list = []
    p = multiprocessing.Process(target=task, args=(data_list,))
    p.start()
    p.join()
    print('end', data_list)  #

2.1共享

通过value和array

通过Manager进行管理

import multiprocessing


def task(d, l):
    d[1] = 1
    d['2'] = 2
    d[0.25] = None
    l.append(123)


if __name__ == "__main__":
    with multiprocessing.Manager() as manger:
        d = manger.dict()
        l = manger.list()

        p = multiprocessing.Process(target=task, args=(d, l))
        p.start()
        p.join()
        print(d)  #
        print(l)  #
# {1: 1, '2': 2, 0.25: None}
# [123

2.2 交换

multiprocessing supports two types of communication channel between process

  • Queues

The Queue class is an near clone of queue.Queue,For example

import multiprocessing
import time


def task(q):
    for i in range(10):
        q.put(i)


if __name__ == "__main__":
    queue=multiprocessing.Queue()
    p = multiprocessing.Process(target=task, args=(queue,))
    p.start()
    p.join()
    print('main process')
    time.sleep(1)
    print(queue.get())
    print(queue.get())
    print(queue.get())
    print(queue.get())
    print(queue.get())
    print(queue.get())
    print(queue.get())
    print(queue.get())
    print(queue.get())
# main process
# 0
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8

ps:实现方法:

输入:queue.put()

输入:queue.get()

  • Pipes

import multiprocessing
import time


def task(conn):
    time.sleep(1)
    conn.send([111,222,333,444])
    data=conn.recv()
    print('subprocess recive:',data)
    time.sleep(2)

if __name__ == "__main__":
    parent_conn,child_conn=multiprocessing.Pipe()
    p = multiprocessing.Process(target=task, args=(child_conn,))
    p.start()
    # p.join()
    info = parent_conn.recv()#阻塞
    print('main process recive',info)
    parent_conn.send(666)
# main process recive [111, 222, 333, 444]
# subprocess recive: 666

3. 进程锁

为了防止多个进程抢占式去做某些操作(同一个资源)的时候,出现操作问题,可以通过进程锁来控制进程的切换

import multiprocessing
import time


def task(n):
    n.value = n.value + 1


if __name__ == "__main__":
    num = multiprocessing.Value('i', 0)

    for i in range(100):
        p = multiprocessing.Process(target=task, args=(num,))
        p.start()
    # time.sleep(3)
    print(num.value)

进程锁:

import multiprocessing
import time


def task(lock):
    print('start')
    lock.acquire()
    with open('f1.txt', mode='r', encoding='utf-8') as f:
        current_n = int(f.read())
    print(current_n)
    time.sleep(1)
    print('doing')
    current_n -= 1
    with open('f1.txt', mode='w', encoding='utf-8') as f:
        f.write(str(current_n))
    lock.release()


if __name__ == "__main__":
    multiprocessing.set_start_method('spawn')
    lock = multiprocessing.RLock()
    process_list = []
    for i in range(10):
        p = multiprocessing.Process(target=task, args=(lock,))
        p.start()
        process_list.append(p)

    # 'spawn'特殊处理
    for item in process_list:
        item.join()

    print('main process end')

4.进程池

import time
from concurrent.futures import ProcessPoolExecutor


def task(num):
    print('dong', num)
    time.sleep(2)


if __name__ == "__main__":
    pool = ProcessPoolExecutor(4)
    for i in range(10):
        pool.submit(task, i)
import multiprocessing
import time
from concurrent.futures import ProcessPoolExecutor


def task(num):
    print('dong', num)
    time.sleep(2)
    return num
def done(res):
    print(multiprocessing.current_process())
    time.sleep(1)
    print(res.result())
    time.sleep(1)


if __name__ == "__main__":
    pool = ProcessPoolExecutor(4)
    for i in range(10):
        pool.submit(task, i).add_done_callback(done)##done有mainProcess处理,线程池中由subthreading处理

    pool.shutdown(True)
    print('main end')

ps:如果在进程池中使用进程锁,字需要基于Manager中的Lock和Rlock来实现

import multiprocessing
import time
from concurrent.futures import ProcessPoolExecutor


def task(lock, ):
    print('start')
    with lock:
        # print('doing', lock)
        time.sleep(2)
        with open('f1.txt', mode='r', encoding='utf=8') as f:
            num = int(f.read())
        num -= 1
        with open('f1.txt', mode='w', encoding='utf=8') as f:
            f.write(str(num))


if __name__ == "__main__":
    pool = ProcessPoolExecutor(4)

    # lock_obj=multiprocessing.RLock()#不能使用
    lock_obj = multiprocessing.Manager().RLock()
    for i in range(10):
        pool.submit(task, lock_obj)  ##done有mainProcess处理,线程池中由subthreading处理

    pool.shutdown(True)

    print('main end')

5.协程

协程:可以称之为微线程,是一种用户态内的上下文的切换技术

  • greenlet

pip insatll greenlet
from greenlet import greenlet


def fun1():
    print(1) #第一步:print 1
    gr2.switch()#第2步:切换到func2
    print(2)#第5步:print 2
    gr2.switch()#第6步:切换到func2从上一次执行的位置继续向后执行


def fun2():
    print(3)#第3步:print 3
    gr1.switch()#第4步:切换到func1,从上一次执行的位置继续向后执行
    print(4)#第7步:print4


gr1 = greenlet(fun1)
gr2 = greenlet(fun2)
gr1.switch()#第0步执行gr1


1
3
2
4
  • yield

def fun1():
    yield 1
    yield from fun2()
    yield 2

def fun2():
    yield 3
    yield 4

f=fun1()
for i in f:
    print(i)

上述两种方式均可实现协程,但是这种编码方式没有意义

来回的切换,会使程式变的更慢

协程有意义

不是手动切换,而是遇到IO操作时自动切换

asynico,async,等模块,内部基于协程并且遇到IO操作请求自动切换

import asyncio


async def fun1():
    print(1)
    await asyncio.sleep(2)#线程等待2s
    print(2)


async def fun2():
    print(3)
    await asyncio.sleep(2)#线程等待2s
    print(4)

task=[
    asyncio.ensure_future(fun1()),
    asyncio.ensure_future(fun2())
]
loop=asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(task))
结果:
1
3
2
4

通过以上内容,在处理IO请求时,协程通过一个线程就可以实现并发的操作

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Windows系统中,多进程开发可以使用Windows API或者第三方库实现。以下是一个简单的多进程示例代码: ```c++ #include <windows.h> #include <iostream> using namespace std; int main() { STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); ZeroMemory(&pi, sizeof(pi)); // 创建子进程 if (!CreateProcess(TEXT("child.exe"), NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { cerr << "Failed to create process." << endl; return 1; } // 等待子进程结束 WaitForSingleObject(pi.hProcess, INFINITE); // 关闭句柄 CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return 0; } ``` 在这个示例中,我们使用了Windows API中的CreateProcess函数创建了一个子进程,并使用WaitForSingleObject函数等待子进程结束。需要注意的是,在使用CreateProcess函数时需要填写STARTUPINFO和PROCESS_INFORMATION结构体,其中STARTUPINFO结构体用来指定子进程的一些属性,如标准输入输出句柄,PROCESS_INFORMATION结构体用来接收子进程的句柄和线程句柄。 在子进程中,我们可以使用类似的方式创建进程: ```c++ #include <windows.h> #include <iostream> using namespace std; int main() { cout << "Child process is running." << endl; return 0; } ``` 这是一个简单的示例,实际应用中可能需要更加复杂的进程间通信和同步机制。可以使用Windows API中的管道、共享内存等机制实现。同时,也可以使用第三方库如Boost和Qt等来简化多进程开发

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值