首页 > 编程语言 >python 多线程

python 多线程

时间:2023-08-22 11:14:44浏览次数:65  
标签:__ python args time print 多线程 id conn

在python中,I/O密集型任务可以用多线程的方式来实现(threading库);然而,对于计算密集型任务,由于python中全局锁GIL的存在,多线程并不能起到一个加速的作用。所以此时,一般使用多进程的方式实现(multiprocessing库)。

多线程 threading: 一个人有与异性聊天和看剧两件事要做。单线程的她可以看完剧再去聊天,但这样子可能就没人陪她聊天了「哼,发消息不回」。我们把她看成一个CPU核心,为她开起多线程——先看一会剧,偶尔看看新消息,在两件事(线程)间来回切换。多线程:单个CPU核心可以同时做几件事,不至于卡在某一步傻等着。

用处:爬取网站信息(爬虫),等待多个用户输入

threading因为python全局锁的关系,实际是只用了cpu的一个核参与计算,所以适合io密集型的任务,在io计算时候,cpu可以进行别的任务计算

多进程 processing: 一个人有很多砖需要搬,他领取手套、推车各种物资(向系统申请了资源)然后开始搬砖。然而他身边有很多人,我们让这些人去帮他!(一核有难,八核围观)。于是他们做了分工,砖很快就搬完了。多进程让多个CPU核心可以一起做事,不至于只有一人干活而其他人傻站着。

用处:进行高性能计算。只有多进程方案设计合理,才能加速计算。

multiprocessing库是实现了cpu的多核,实现并行计算,进行多进程

def function1(id):  # 这里是子进程
    print(f'id {id}')

def run__process():  # 这里是主进程
    from multiprocessing import Process
    process = [mp.Process(target=function1, args=(1,)),
               mp.Process(target=function1, args=(2,)), ]
    [p.start() for p in process]  # 开启了两个进程
    [p.join() for p in process]   # 等待两个进程依次结束

# run__process()  # 主线程不建议写在 if外部。由于这里的例子很简单,你强行这么做可能不会报错
if __name__ =='__main__':
    run__process()  # 正确做法:主线程只能写在 if内部

Python多进程可以选择两种创建进程的方式,spawn 与 fork。分支创建:fork会直接复制一份自己给子进程运行,并把自己所有资源的handle 都让子进程继承,因而创建速度很快,但更占用内存资源。分产创建:spawn只会把必要的资源的handle 交给子进程,因此创建速度稍慢。详细解释请看 Stack OverFlow multiprocessing fork vs spawn 。(分产spawn 是我自己随便翻译的,有更好的翻译请推荐。我绝不把handle 翻译成句柄)

multiprocessing.set_start_method('spawn')  # default on WinOS or MacOS
multiprocessing.set_start_method('fork')   # default on Linux (UnixOS)

请注意:我说 分支fork 在初始化创建多进程的时候比 分产spawn 快,而不是说高性能计算会比较快。通常高性能计算需要让程序运行很久,因此为了节省内存以及进程安全,我建议选择 spawn。

进程池 Pool

几乎Python多进程代码都需要你明明白白地调用Process。而进程池Pool 会自动帮我们管理子进程。Python的Pool 不方便传入多个参数,我这里提供两个解决思路:

思路1:函数 func2 需要传入多个参数,现在把它改成一个参数,无论你直接让args作为一个元组tuple、词典dict、类class都可以

作者:曾伊言
链接:https://zhuanlan.zhihu.com/p/340657122
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

import time

def func2(args):  # multiple parameters (arguments)
    # x, y = args
    x = args[0]  # write in this way, easier to locate errors
    y = args[1]  # write in this way, easier to locate errors

    time.sleep(1)  # pretend it is a time-consuming operation
    return x - y


def run__pool():  # main process
    from multiprocessing import Pool

    cpu_worker_num = 3
    process_args = [(1, 1), (9, 9), (4, 4), (3, 3), ]

    print(f'| inputs:  {process_args}')
    start_time = time.time()
    with Pool(cpu_worker_num) as p:
        outputs = p.map(func2, process_args)
    print(f'| outputs: {outputs}    TimeUsed: {time.time() - start_time:.1f}    \n')

    '''Another way (I don't recommend)
    Using 'functions.partial'. See https://stackoverflow.com/a/25553970/9293137
    from functools import partial
    # from functools import partial
    # pool.map(partial(f, a, b), iterable)
    '''

if __name__ =='__main__':
    run__pool()

管道 Pipe

顾名思义,管道Pipe 有两端,因而 main_conn, child_conn = Pipe() ,管道的两端可以放在主进程或子进程内,我在实验中没发现主管道口main_conn 和子管道口child_conn 的区别。两端可以同时放进去东西,放进去的对象都经过了深拷贝:用 conn.send()在一端放入,用 conn.recv() 另一端取出,管道的两端可以同时给多个进程。conn是 connect的缩写。

import time

def func_pipe1(conn, p_id):
    print(p_id)

    time.sleep(0.1)
    conn.send(f'{p_id}_send1')
    print(p_id, 'send1')

    time.sleep(0.1)
    conn.send(f'{p_id}_send2')
    print(p_id, 'send2')

    time.sleep(0.1)
    rec = conn.recv()
    print(p_id, 'recv', rec)

    time.sleep(0.1)
    rec = conn.recv()
    print(p_id, 'recv', rec)


def func_pipe2(conn, p_id):
    print(p_id)

    time.sleep(0.1)
    conn.send(p_id)
    print(p_id, 'send')
    time.sleep(0.1)
    rec = conn.recv()
    print(p_id, 'recv', rec)


def run__pipe():
    from multiprocessing import Process, Pipe

    conn1, conn2 = Pipe()

    process = [Process(target=func_pipe1, args=(conn1, 'I1')),
               Process(target=func_pipe2, args=(conn2, 'I2')),
               Process(target=func_pipe2, args=(conn2, 'I3')), ]

    [p.start() for p in process]
    print('| Main', 'send')
    conn1.send(None)
    print('| Main', conn2.recv())
    [p.join() for p in process]

if __name__ =='__main__':
    run__pipe()

Pipe还有 duplex参数poll() 方法 需要了解。默认情况下 duplex==True,若不开启双向管道,那么传数据的方向只能 conn1 ← conn2 。conn2.poll()==True 意味着可以马上使用 conn2.recv() 拿到传过来的数据。conn2.poll(n) 会让它等待n秒钟再进行查询。

from multiprocessing import Pipe

conn1, conn2 = Pipe(duplex=True)  # 开启双向管道,管道两端都能存取数据。默认开启
# 
conn1.send('A')
print(conn1.poll())  # 会print出 False,因为没有东西等待conn1去接收
print(conn2.poll())  # 会print出 True ,因为conn1 send 了个 'A' 等着conn2 去接收
print(conn2.recv(), conn2.poll(2))  # 会等待2秒钟再开始查询,然后print出 'A False'

  

  



标签:__,python,args,time,print,多线程,id,conn
From: https://www.cnblogs.com/qiaoqifa/p/17648006.html

相关文章

  • Lnton羚通云算力平台如何在OpenCV-Python 中,来进行图像算术运算?
    在OpenCV-Python中,可以使用函数cv2.add()、cv2.subtract()、cv2.multiply()和cv2.divide()来进行图像算术运算。这些函数接受两个输入图像,并对其进行逐像素的运算。1.图像加法:OpenCV 是饱和运算(大于255算255),NumPy 是模运算(大于255会与256进行求模)。importnumpyasnpimpo......
  • Python中字符串截取
    #截取字符串时,如果位数不够,Python不会报错,而是返回空字符串#这是因为Python中的字符串是不可变的,所以当我们尝试访问一个不存在的索引时,Python会返回空字符串而不是报错#示例代码s='hello'print(s[10:15])#返回空字符串'' #Python中的字符串是不可变的,这意味着一旦......
  • vscode 配置 python black 格式化单行长度
    配置信息vscode版本1.81.1vscode安装BlackFormatter插件问题默认Black格式化之后单行长度太短,需要通过修改配置文件解决。方法Ctrl+Shift+p,打开settings.json,添加一个black-formatter.args配置项,如下所示:"black-formatter.args":["--line-le......
  • python 外部文件调用Django程序操作model
    importosimportdjango#设置Django配置文件文件夹所在位置,并进行系统环境配置os.environ.setdefault("DJANGO_SETTINGS_MODULE","项目配置文件夹名称.settings")#加载Django模块,初始化Django环境django.setup()#导入需要调用的modelfrom应用名称.modelsimport......
  • Qt 多线程简单应用
    声明:QThread*thread;初始化:thread=newQThread();thread->start();将对象放到线程中去:moveToThread(thread);readTimer.moveToThread(thread);readTimer.setSingleShot(true);连接消亡信号:connect(thread,SIGNAL(finished()),this,SLOT(thread_done()));注......
  • python 打印一个条形图?
    背景在python中,使用matplot生成图表是一个很常用的方法,但在一些轻量级需求场合,例如仅做一个打印预览,或者快速查看,这些场景下调用matplot生成图表,略显繁琐。今天介绍一个通过 DebugInfo 模块打印条形图的方法,简单实用。引入模块pipinstallDebugInfo打印销售转化数据下面的......
  • 搭建Python⾃带静态Web服务器
    说明Python自带的静态Web服务器可以通过使用http.server模块来实现。步骤打开命令行终端,进入要作为静态文件根目录的文件夹。运行以下命令启动静态Web服务器:Python2.x版本:python-mSimpleHTTPServer<port>Python3.x版本:python-mhttp.server<port> <port>是可选参......
  • Python中的 if __name__ == “__main__“
    ✅作者简介:热爱科研的算法开发者,Python、Matlab项目可交流、沟通、学习。......
  • python设置全局热键
    需要使用第三方库,代码如下:importtkinterastkimportkeyboarddefoutput(event):#print("Fromglobalkeystroke")print(event)root=tk.Tk()root.withdraw()keyboard.add_hotkey('ctrl+a',output,args=('Fromglobalkeystroke'......
  • java中多线程使用方法
    线程互相独立可以同时运行一个线程不能多次启用并发和并行并发强调交替并行强调同时多线程实现方式继承Thread重写run方法下不能直接调用方法要调用start方法setname给线程命名getname获取线程名字实现Runnable接口先继承Runnable在创建Thread对象参......