python学习笔记4:多进程和多线程的使用方法和区别

进程
python实现多进程,可以用fork()系统调用,但是不推荐这个方法,因为这个方法Windows没有。
我们还可以用模块multiprocessing,其中的Process类可以用来表示一个进程对象,看一个例子:

from multiprocessing import Process
import os

def run_proc(name):
   print('%s process started, id is %s' % (name,os.getpid()))

if __name__ == '__main__':
    #创建一个子进程,传入一个执行函数和参数
    parePro = Process(target = run_proc, args=('child1',))
    print('Parent started...')
    #子进程开始执行
    parePro.start()


    #调用此方法后,等待子进程运行结束后在继续执行
    parePro.join()
    print('child1 process ended...')

运行结果:

Parent started...
child1 process started, id is 5040
child1 process ended...
[Finished in 0.3s]

上面的例子中,通过Process来创建进程每次只能创建一个进程,还可以使用Pool()方法:

from multiprocessing import Pool
import os, time, random

def long_time_task(name):
    print('Run task %s (%s)...' % (name, os.getpid()))
    start = time.time()
    time.sleep(random.random() * 3)
    end = time.time()
    print('Task %s runs %0.2f seconds.' % (name, (end - start)))

if __name__=='__main__':
    print('Parent process %s.' % os.getpid())
    #参数5代表最多创建5个进程,所以下面的for循环
    #中创建5个进程后,就不在继续创建,而是在等待
    #前几个进程运行完毕后再继续创建进程
    p = Pool(5)
    for i in range(10):
        p.apply_async(long_time_task, args=(i,))
    print('Waiting for all subprocesses done...')
    #调用此方法后不再创建进程
    p.close()
    p.join()
    print('All subprocesses done.')

再来看进程间进行通信的实现,是通过python提供的Queue()模块实现的,一个进程往队列里写数据,另一个读数据:

from multiprocessing import Process,Queue
import os,time,random

def write(q):
    print('Process to write: %s' % os.getpid())
    for value in ['A','B','C']:
        print('%s to queue...' % value)
        q.put(value)
        time.sleep(random.random())
        time.sleep(3)

def read(q):
    print('Process to read:%s' % os.getpid())
    while True:
        value = q.get(True)
        print('get %s from queue' % value)

if __name__ == '__main__':
    q = Queue()
    childPro_Write = Process(target=write, args=(q,))
    childPro_read = Process(target=read, args=(q,))
    childPro_Write.start()

    childPro_read.start()
    childPro_Write.join()

    #读数据是个死循环,所以调用此方法
    childPro_read.terminate()
    print('end...')

注意:上述两个例子的代码我在windows系统中执行感觉有点问题,最后结果不太对,但是放在linux(ubuntu16.04)中执行没有问题,具体原因我也不太清楚。

线程
线程的使用方法与进程类似,通过调用Threading模块实现:

import time, threading

#创建一个线程的例子
def loop():
    print('thread %s runs...' % threading.current_thread().name)
    n = 0
    while n < 5:
        n += 1
        print('threading %s >>> %s' % (threading.current_thread().name, n))
        time.sleep(1)
    print('thread %s ended' % threading.current_thread().name)

print('thread %s runs...' % threading.current_thread().name)
#创建线程的时候通过参数name来为线程定义一个名字
t = threading.Thread(target=loop, name='childThread')
t.start()
t.join()
print('thread %s ended' % threading.current_thread().name)

运行结果:

thread MainThread runs...
thread childThread runs...
threading childThread >>> 1
threading childThread >>> 2
threading childThread >>> 3
threading childThread >>> 4
threading childThread >>> 5
thread childThread ended
thread MainThread ended
[Finished in 5.1s]

当线程修改全局变量时,如果不添加锁的操作,可能会使结果出现问题,锁操作的用法:
首先在主线程处定义lock = threading.Lock()
在线程的运行函数中对全局变量的部分改为:

#         lock.acquire()
#         锁操作,相当于声明此刻只有我这个线程能进行修改全局变量的操作,其他线程必须等待
#         try:
#             #修改全局变量的操作
#         finally:
#             lock.release()
#             声明其他线程能进行全局变量的修改操作了

锁操作能保证代码的正确执行,但是锁操作坏处也有很多,阻止了多线程并发执行,效率大大下降,还很有可能造成死锁。

在多线程中,每个线程都会从主线程得到一些数据作为自己的局部变量,不受其他线程干扰进行独立处理,在主线程函数调用通过参数传递给子线程这些数据时会有一些麻烦,另外最笨的方法是建一个全局字典,每个子线程有对应key和value值;还有一个办法就是使用ThreadLocal

import threading

local_heros = threading.local()

def process_heros():
    hero_name = local_heros.hero_name
    print('Hello, %s! (in %s)' % (hero_name, threading.current_thread().name))

def process_thread(name):
    local_heros.hero_name = name
    process_heros()

t1 = threading.Thread(target=process_thread, args=('阿狸',), name='thread-LoL_heros')
t2 = threading.Thread(target=process_thread, args=('路飞',), name='thread-OnePiece_heros')
t1.start()
t2.start()
t1.join()
t2.join()

#ThreadLocal最常用的地方就是为每个线程绑定一个数据库连接,HTTP请求,用户身份信息等,这样一个线程的所有调用到的处理函数都可以非常方便地访问这些资源。

进程与线程的区别
多进程的优点就是多进程稳定性高,一个子进程崩溃,不会影响其他进程的执行。缺点是创建进程开销大,并且同时运行的进程数也是有限的。

多线性比多进程稍微快一点,缺点出了上面说的锁操作外,还容易使进程崩溃,因为所有现存共享进程的内存,一个进程崩溃会使整个进程崩溃。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值