返回顶部
首页 > 资讯 > 后端开发 > Python >第十五章 Python多进程与多线程
  • 666
分享到

第十五章 Python多进程与多线程

十五章多线程进程 2023-01-31 06:01:36 666人浏览 泡泡鱼

Python 官方文档:入门教程 => 点击学习

摘要

15.1 multiprocessingmultiprocessing是多进程模块,多进程提供了任务并发性,能充分利用多核处理器。避免了GIL(全局解释锁)对资源的影响。有以下常用类:类描述Process(group=None, targe

15.1 multiprocessing

multiprocessing是多进程模块,多进程提供了任务并发性,能充分利用多核处理器。避免了GIL(全局解释)对资源的影响。

有以下常用类:

描述

Process(group=None, target=None, name=None, args=(), kwargs={})派生一个进程对象,然后调用start()方法启动

Pool(processes=None, initializer=None, initargs=())

返回一个进程池对象,processes进程池进程数量
Pipe(duplex=True)返回两个连接对象由管道连接
Queue(maxsize=0)返回队列对象,操作方法跟Queue.Queue一样
multiprocessing.dummy这个库是用于实现多线程

Process()类有以下些方法:

run()
start()启动进程对象
join([timeout])等待子进程终止,才返回结果。可选超时。
name进程名字
is_alive()返回进程是否存活
daemon进程的守护标记,一个布尔值
pid返回进程ID
exitcode子进程退出状态码
terminate()终止进程。在unix上使用SIGTERM信号,在windows上使用TerminateProcess()。

Pool()类有以下些方法:

apply(func, args=(), kwds={})等效内建函数apply()
apply_async(func, args=(), kwds={}, callback=None)异步,等效内建函数apply()
map(func, iterable, chunksize=None)等效内建函数map()
map_async(func, iterable, chunksize=None, callback=None)异步,等效内建函数map()
imap(func, iterable, chunksize=1)等效内建函数itertools.imap()
imap_unordered(func, iterable, chunksize=1)像imap()方法,但结果顺序是任意的
close()关闭进程池
terminate()终止工作进程,垃圾收集连接池对象
join()等待工作进程退出。必须先调用close()或terminate()

Pool.apply_async()和Pool.map_aysnc()又提供了以下几个方法:

get([timeout])获取结果对象里的结果。如果超时没有,则抛出TimeoutError异常
wait([timeout])等待可用的结果或超时
ready()返回调用是否已经完成
successful()

举例:

1)简单的例子,用子进程处理函数

from multiprocessing import Process
import os
def worker(name):
    print name
    print 'parent process id:', os.getppid()
    print 'process id:', os.getpid()
if __name__ == '__main__':
    p = Process(target=worker, args=('function worker.',))
    p.start()
    p.join()
    print p.name
    
# python test.py
function worker.
parent process id: 9079
process id: 9080
Process-1

Process实例传入worker函数作为派生进程执行的任务,用start()方法启动这个实例。

2)加以说明join()方法

from multiprocessing import Process
import os
def worker(n):
    print 'hello world', n
if __name__ == '__main__':
    print 'parent process id:', os.getppid()
    for n in range(5):
        p = Process(target=worker, args=(n,))
        p.start()
        p.join()
        print 'child process id:', p.pid
        print 'child process name:', p.name
        
# Python test.py
parent process id: 9041
hello world 0
child process id: 9132
child process name: Process-1
hello world 1
child process id: 9133
child process name: Process-2
hello world 2
child process id: 9134
child process name: Process-3
hello world 3
child process id: 9135
child process name: Process-4
hello world 4
child process id: 9136
child process name: Process-5

# 把p.join()注释掉再执行
# python test.py
parent process id: 9041
child process id: 9125
child process name: Process-1
child process id: 9126
child process name: Process-2
child process id: 9127
child process name: Process-3
child process id: 9128
child process name: Process-4
hello world 0
hello world 1
hello world 3
hello world 2
child process id: 9129
child process name: Process-5
hello world 4

可以看出,在使用join()方法时,输出的结果都是顺序排列的。相反是乱序的。因此join()方法是堵塞父进程,要等待当前子进程执行完后才会继续执行下一个子进程。否则会一直生成子进程去执行任务。

在要求输出的情况下使用join()可保证每个结果是完整的。

3)给子进程命名,方便管理

from multiprocessing import Process
import os, time
def worker1(n):
    print 'hello world', n
def worker2():
    print 'worker2...'
if __name__ == '__main__':
    print 'parent process id:', os.getppid()
    for n in range(3):
        p1 = Process(name='worker1', target=worker1, args=(n,))
        p1.start()
        p1.join()
        print 'child process id:', p1.pid
        print 'child process name:', p1.name
    p2 = Process(name='worker2', target=worker2)
    p2.start()
    p2.join()
    print 'child process id:', p2.pid
    print 'child process name:', p2.name
    
# python test.py
parent process id: 9041
hello world 0
child process id: 9248
child process name: worker1
hello world 1
child process id: 9249
child process name: worker1
hello world 2
child process id: 9250
child process name: worker1
worker2...
child process id: 9251
child process name: worker2

4)设置守护进程,父进程退出也不影响子进程运行

from multiprocessing import Process
def worker1(n):
    print 'hello world', n
def worker2():
    print 'worker2...'
if __name__ == '__main__':
    for n in range(3):
        p1 = Process(name='worker1', target=worker1, args=(n,))
        p1.daemon = True
        p1.start()
        p1.join()
    p2 = Process(target=worker2)
    p2.daemon = False
    p2.start()
    p2.join()

5)使用进程池

#!/usr/bin/python
# -*- coding: utf-8 -*-
from multiprocessing import Pool, current_process
import os, time, sys
def worker(n):
    print 'hello world', n
    print 'process name:', current_process().name  # 获取当前进程名字
    time.sleep(1)    # 休眠用于执行时有时间查看当前执行的进程
if __name__ == '__main__':
    p = Pool(processes=3)
    for i in range(8):
        r = p.apply_async(worker, args=(i,))
        r.get(timeout=5)  # 获取结果中的数据
    p.close()
    
# python test.py
hello world 0
process name: PoolWorker-1
hello world 1
process name: PoolWorker-2
hello world 2
process name: PoolWorker-3
hello world 3
process name: PoolWorker-1
hello world 4
process name: PoolWorker-2
hello world 5
process name: PoolWorker-3
hello world 6
process name: PoolWorker-1
hello world 7
process name: PoolWorker-2

进程池生成了3个子进程,通过循环执行8次worker函数,进程池会从子进程1开始去处理任务,当到达最大进程时,会继续从子进程1开始。

在运行此程序同时,再打开一个终端窗口会看到生成的子进程:

# ps -ef |grep python
root      40244   9041  4 16:43 pts/3   00:00:00 python test.py
root      40245  40244  0 16:43 pts/3    00:00:00 python test.py
root      40246  40244  0 16:43 pts/3    00:00:00 python test.py
root      40247  40244  0 16:43 pts/3    00:00:00 python test.py

6)进程池map()方法

map()方法是将序列中的元素通过函数处理返回新列表。

from multiprocessing import Pool
def worker(url):
    return 'Http://%s' % url
urls = ['www.baidu.com', 'www.jd.com']
p = Pool(processes=2)
r = p.map(worker, urls)
p.close()
print r

# python test.py
['http://www.baidu.com', 'http://www.jd.com']

7)Queue进程间通信

multiprocessing支持两种类型进程间通信:Queue和Pipe。

Queue库已经封装到multiprocessing库中,在第十章 Python常用标准库已经讲解到Queue库使用,有需要请查看以前博文。

例如:一个子进程向队列写数据,一个子进程读取队列数据

#!/usr/bin/python
# -*- coding: utf-8 -*-
from multiprocessing import Process, Queue
# 写数据到队列
def write(q):
    for n in range(5):
        q.put(n)
        print 'Put %s to queue.' % n
# 从队列读数据
def read(q):
    while True:
        if not q.empty():
            value = q.get()
            print 'Get %s from queue.' % value
        else:
            break
if __name__ == '__main__':
    q = Queue()
    pw = Process(target=write, args=(q,))
    pr = Process(target=read, args=(q,))   
    pw.start()
    pw.join()
    pr.start()
    pr.join()
    
# python test.py
Put 0 to queue.
Put 1 to queue.
Put 2 to queue.
Put 3 to queue.
Put 4 to queue.
Get 0 from queue.
Get 1 from queue.
Get 2 from queue.
Get 3 from queue.
Get 4 from queue.

8)Pipe进程间通信

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() 
    p.join()
    
# python test.py
[42, None, 'hello']

Pipe()创建两个连接对象,每个链接对象都有send()和recv()方法,

9)进程间对象共享

Manager类返回一个管理对象,它控制服务端进程。提供一些共享方式:Value()、Array()、list()、dict()、Event()等

创建Manger对象存放资源,其他进程通过访问Manager获取。

from multiprocessing import Process, Manager
def f(v, a, l, d):
    v.value = 100
    a[0] = 123
    l.append('Hello')
    d['a'] = 1
mgr = Manager()
v = mgr.Value('v', 0)
a = mgr.Array('d', range(5))
l = mgr.list()
d = mgr.dict()
p = Process(target=f, args=(v, a, l, d))
p.start()
p.join()
print(v)
print(a)
print(l)
print(d)

# python test.py
Value('v', 100)
array('d', [123.0, 1.0, 2.0, 3.0, 4.0])
['Hello']
{'a': 1}

10)写一个多进程的例子

比如:多进程监控URL是否正常

from multiprocessing import Pool, current_process
import urllib2
urls = [
    'http://www.baidu.com',
    'http://www.jd.com',
    'http://www.sina.com',
    'http://www.163.com',
]
def status_code(url):
    print 'process name:', current_process().name
    try:
        req = urllib2.urlopen(url, timeout=5)
        return req.getcode()
    except urllib2.URLError:
        return
p = Pool(processes=4)
for url in urls:
    r = p.apply_async(status_code, args=(url,))
    if r.get(timeout=5) == 200:
        print "%s OK" %url
    else:
        print "%s NO" %url
        
# python test.py
process name: PoolWorker-1
http://www.baidu.com OK
process name: PoolWorker-2
http://www.jd.com OK
process name: PoolWorker-3
http://www.sina.com OK
process name: PoolWorker-4
http://www.163.com OK


博客地址:http://lizhenliang.blog.51cto.com

QQ群:323779636(shell/Python运维开发群)


15.2 threading

threading模块类似于multiprocessing多进程模块,使用方法也基本一样。threading库是对thread库进行二次封装,我们主要用到Thread类,用Thread类派生线程对象。

1)使用Thread类实现多线程

from threading import Thread, current_thread
def worker(n):
    print 'thread name:', current_thread().name
    print 'hello world', n
    
for n in range(5):
    t = Thread(target=worker, args=(n, ))
    t.start()
    t.join()  # 等待主进程结束
    
# python test.py
thread name: Thread-1
hello world 0
thread name: Thread-2
hello world 1
thread name: Thread-3
hello world 2
thread name: Thread-4
hello world 3
thread name: Thread-5
hello world 4

2)还有一种方式继承Thread类实现多线程,子类可以重写__init__和run()方法实现功能逻辑。

#!/usr/bin/python
# -*- coding: utf-8 -*-
from threading import Thread, current_thread
class Test(Thread):
    # 重写父类构造函数,那么父类构造函数将不会执行
    def __init__(self, n):
        Thread.__init__(self)
        self.n = n
    def run(self):
        print 'thread name:', current_thread().name
        print 'hello world', self.n
if __name__ == '__main__':
    for n in range(5):
        t = Test(n)
        t.start()
        t.join()
        
# python test.py
thread name: Thread-1
hello world 0
thread name: Thread-2
hello world 1
thread name: Thread-3
hello world 2
thread name: Thread-4
hello world 3
thread name: Thread-5
hello world 4

3)Lock

from threading import Thread, Lock, current_thread
lock = Lock()
class Test(Thread):
    # 重写父类构造函数,那么父类构造函数将不会执行
    def __init__(self, n):
        Thread.__init__(self)
        self.n = n
    def run(self):
        lock.acquire()  # 获取锁
        print 'thread name:', current_thread().name
        print 'hello world', self.n
        lock.release()  # 释放锁
if __name__ == '__main__':
    for n in range(5):
        t = Test(n)
        t.start()
        t.join()

众所周知,Python多线程有GIL全局锁,意思是把每个线程执行代码时都上了锁,执行完成后会自动释放GIL锁,意味着同一时间只有一个线程在运行代码。由于所有线程共享父进程内存、变量、资源,很容易多个线程对其操作,导致内容混乱。

当你在写多线程程序的时候如果输出结果是混乱的,这时你应该考虑到在不使用锁的情况下,多个线程运行时可能会修改原有的变量,导致输出不一样。

由此看来Python多线程是不能利用多核CPU提高处理性能,但在IO密集情况下,还是能提高一定的并发性能。也不必担心,多核CPU情况可以使用多进程实现多核任务。Python多进程是复制父进程资源,互不影响,有各自独立的GIL锁,保证数据不会混乱。能用多进程就用吧!


--结束END--

本文标题: 第十五章 Python多进程与多线程

本文链接: https://lsjlt.com/news/189338.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 第十五章 Python多进程与多线程
    15.1 multiprocessingmultiprocessing是多进程模块,多进程提供了任务并发性,能充分利用多核处理器。避免了GIL(全局解释锁)对资源的影响。有以下常用类:类描述Process(group=None, targe...
    99+
    2023-01-31
    十五章 多线程 进程
  • python之多线程与多进程
    1. 多进程与多线程 (1)背景:为何需要多进程或者多线程:在同一时间里,同一个计算机系统中如果允许两个或者两个以上的进程处于运行状态,这便是多任务。多任务会带来的好处例如用户边听歌、边上网、边打印,而这些任务之间丝毫不会互相干扰。使用多...
    99+
    2023-01-31
    之多 线程 进程
  • Python 多进程开发与多线程开发
    我们先来了解什么是进程?程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程。程序和进程的区别就在于:程序是指令的集合,它是进程运行的静态描述文本;进程是程序的一次执行活动,属于动态概念。在多道...
    99+
    2023-01-31
    多线程 进程 Python
  • python 多线程与多进程效率测试
    目录1、概述2、代码练习3、运行结果1、概述 在Python中,计算密集型任务适用于多进程,IO密集型任务适用于多线程 正常来讲,多线程要比多进程效率更高,因为进程间的切换需要的资...
    99+
    2024-04-02
  • python多线程与多进程--存活主机p
    python多线程与多进程 多线程: 案例:扫描给定网络中存活的主机(通过ping来测试,有响应则说明主机存活) 普通版本:   #扫描给定网络中存活的主机(通过ping来测试,有响应则说明主机存活)import sys import ...
    99+
    2023-01-30
    多线程 进程 主机
  • 《Python核心编程》第五章
    5-1.整型。讲讲Python普通整型和长整型的区别?   答案:    在大多数32位机器上,标准整型的取值范围是-2^31~2^31-1,如果在64位机器上使用64位编译器编译的Python,则整型是64位的。而长整型能表示的数值仅仅与...
    99+
    2023-01-31
    第五章 核心 Python
  • python多线程和多进程(二)
    ---恢复内容开始--- 一、多进程   1、multiprocessing模块用来开启子进程,并在子进程中执行我们定制的任务(比如函数),该模块与多线程模块threading的编程接口类似。 import time from mult...
    99+
    2023-01-30
    多线程 进程 python
  • python socket多线程和多进程
    在socket中,如果直接创建的话,是只能接受一个用户的请求需要实现socketserver中的handle方法,可以实现多进程并发访问 SocketServer内部使用 IO多路复用 以及 “多线程” 和 “多进程” ,从而实现并发处理...
    99+
    2023-01-31
    多线程 进程 python
  • Python多线程与多进程相关知识总结
    目录一、什么是进程二、什么是线程三、并发、并行3.1 并发3.2 并行四、多线程适用场景五、Python GIL六、Python多线程、多进程实例:CPU 密集型任务6.1 单线程6...
    99+
    2024-04-02
  • 分析详解python多线程与多进程区别
    目录1 基础知识1.1 线程1.2 进程1.3 两者的区别2 Python 多进程2.1 创建多进程方法1:直接使用Process方法2:继承Process来自定义进程类,重写run...
    99+
    2024-04-02
  • python中多进程与多线程有什么区别
    python中多进程与多线程有什么区别?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。python的数据类型有哪些python的数据类型:1. 数字类型,包括int(整型)、lo...
    99+
    2023-06-14
  • Python 多线程及进程
    threading使用 (工业风案例) import threading from time import sleep, ctime loop = [4, 2] class ThreadFunc: def __init_...
    99+
    2023-01-30
    多线程 进程 Python
  • python多进程和多线程介绍
    目录一、什么是进程和线程 二、多进程和多线程 三、python中的多进程和多线程1、多进程2、多线程一、什么是进程和线程  进程是分配资源的最小单位,线...
    99+
    2024-04-02
  • python——多进程、线程、携程
    http://mp.weixin.qq.com/splg_nld=1&plg_usr=1&scene=23&mid=2652078313&plg_vkey=1&__biz=MzI2NjA3NTc4Ng...
    99+
    2023-01-31
    线程 携程 进程
  • 第十七章 Python网络编程
    Socket简介在网络上的两个程序通过一个双向的通信连接实现数据的交换,这个链接的一端称为一个Socket(套接字),用于描述IP地址和端口。建立网络通信连接至少要一对端口号(Socket),Socket本质是编程接口(API),对TCP/...
    99+
    2023-01-31
    十七章 网络编程 Python
  • Python控制多进程与多线程并发数总结
    一、前言 本来写了脚本用于暴力破解密码,可是1秒钟尝试一个密码2220000个密码我的天,想用多线程可是只会一个for全开,难道开2220000个线程吗?只好学习控制线程数了,官方文档不好看,觉得结构不够...
    99+
    2022-06-04
    多线程 进程 Python
  • Python 多进程 多线程数据共享
    #!/usr/bin/env python # -*- coding:utf-8 -*- # author: Changhua Gong from multiprocessing import Process, Queue import o...
    99+
    2023-01-31
    多线程 进程 数据
  • Python多进程与多线程的使用场景有哪些
    这篇文章主要介绍Python多进程与多线程的使用场景有哪些,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!前言Python多进程适用的场景:计算密集型(CPU密集型)任务Python多线程适用的场景:IO密集型任务计算...
    99+
    2023-06-07
  • 第十三章 Python数据库编程
    本章节讲解Python操作数据库,完成简单的增删改查工作,以MySQL数据库为例。Python的MySQL数据库操作模块叫MySQLdb,需要额外的安装下。通过pip工具安装:pip install MyS...
    99+
    2024-04-02
  • python 多进程和多线程使用详解
    目录进程和线程 Python的多进程 进程池 多进程间的数据通信与共享 Python的多线程 多线程间的数据共享 使用queue队列通信-经典的生产者和消费者模型进程和线程 进程是...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作