python多线程(二)

如果使用Pool创建进程,就需要使用multiprocessing.Manager()中的Queue()来完成进程间的通信,而不是multiprocessing.Queue(),否则会抛出如下异常。RuntimeError: Queue objects should only be shared between processes through inheritance

from multiprocessing import Manager,Pool
import time
def write(q):
    #将列表中的元素写入队列中
    for i in ["a","b","c"]:
        print('开始写入值%s' % i)
        q.put(i)
        time.sleep(1)

#读取
def read(q):
    print('开始读取')
    while True:
        if not q.empty():
            print('读取到:',q.get())
            time.sleep(1)
        else:
            break
if __name__=='__main__':
    #创建队列
    q=Manager().Queue()
    #创建进程池
    p=Pool(3)
    #使用阻塞模式创建进程
    p.apply(write,(q,))
    p.apply(read,(q,))
    p.close()
    p.join()

线程:

进程和线程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护,而进程正相反。

在Python程序中,可以通过“_thread”和threading(推荐使用)这两个模块来处理线程。在Python3中,thread模块已经废弃。可以使用threading模块代替。所以,在Python3中不能再使用thread模块,但是为了兼容Python3以前的程序,在Python3中将thread模块重命名为“_thread”。

在Python程序中,可以通过两种方式来使用线程:使用函数或者使用类来包装线程对象。当使用thread模块来处理线程时,可以调用里面的函数start_new_thread()来生成一个新的线程,语法格式如下:

_thread.start_new_thread ( function, args[, kwargs] )

其中function是线程函数;args表示传递给线程函数的参数,他必须是个tuple类型;kwargs 是可选参数。

threading模块

Python3 通过两个标准库 _thread 和 threading 提供对线程的支持。_thread 提供了低级别的、原始的线程以及一个简单的锁,它相比于 threading 模块的功能还是比较有限的。

threading 模块除了包含 _thread 模块中的所有方法外,还提供的其他方法:

  • threading.currentThread(): 返回当前的线程变量。
  • threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
  • threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

在Python3程序中,对多线程支持最好的是threading模块,使用这个模块,可以灵活地创建多线程程序,并且可以在多线程之间进行同步和通信。在Python3程序中,可以通过如下两种方式来创建线程:

  • 通过threading.Thread直接在线程中运行函数
  • 通过继承类threading.Thread来创建线程

在Python中使用threading.Thread的基本语法格式如下所示:

Thread(group=None, target=None, name=None, args=(), kwargs={})

其中target: 要执行的方法;name: 线程名;args/kwargs: 要传入方法的参数。

import threading
import time
def fun1(thread_name,delay):
    print('线程{0}开始运行fun1'.format(thread_name))
    time.sleep(delay)
    print('线程{0}运行fun1结束'.format(thread_name))
def fun2(thread_name,delay):
    print('线程{0}开始运行fun2'.format(thread_name))
    time.sleep(delay)
    print('线程{0}运行fun2结束'.format(thread_name))
if __name__=='__main__':
    print('开始运行')
    #创建线程
    t1=threading.Thread(target=fun1,args=('thread-1',4))
    t2=threading.Thread(target=fun2,args=('thread-2',2))
    t1.start()
    t2.start()

在Python中,通过继承类threading.Thread的方式来创建一个线程。这种方法只要重写类threading.Thread中的方法run(),然后再调用方法start()就能创建线程,并运行方法run()中的代码。

【示例】继承threading.Thread类创建线程

import threading
import time
def fun1(delay):
    print('线程{0}开始运行fun1'.format(threading.current_thread().getName))
    time.sleep(delay)
    print('线程{0}运行fun1结束'.format(threading.current_thread().getName))
def fun2(delay):
    print('线程{0}开始运行fun2'.format(threading.current_thread().getName))
    time.sleep(2)
    print('线程{0}运行fun2结束'.format(threading.current_thread().getName))
#创建线程类继承threading.Thread
class MyThread(threading.Thread):
    #重写父类的构造方法,其中func是线程函数,args是传入线程的参数,name是线程名
    def __init__(self,func,name,args):
        super().__init__(target=func,name=name,args=args)
    #重写父类的run()方法
    def run(self):
        self._target(*self._args)

if __name__=='__main__':
    print('开始运行')
    #创建线程
    t1=MyThread(fun1,'thread-1',(2,))
    t2=MyThread(fun2,'thread-2',(4,))
    t1.start()
    t2.start()

互斥锁

如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步。最简单的同步机制就是引入互斥锁。

锁有两种状态——锁定和未锁定。某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”状态,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。

使用 Thread 对象的 Lock 可以实现简单的线程同步,有上锁 acquire 方法和 释放release 方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到 acquire 和 release 方法之间。

【示例】互斥锁

import time
from threading import Thread,Lock
#定义全局变量num
num=0
#创建一把互斥锁
mutex=Lock()
def test1():
    global num
    '''
    在两个线程中都调用上锁的方法,则这两个线程就会抢着上锁,
    如果有1方成功上锁,那么导致另外一方会堵塞(一直等待)直到这个锁被解开
    '''
    mutex.acquire()#上锁
    for i in range(100000):
        num+=1
    mutex.release()
    print('test1输出num:',num)

def test2():
    global num
    mutex.acquire()  # 上锁
    for i in range(100000):
        num+=1
    mutex.release()
    print('test2输出num:',num)

if __name__=='__main__':
    t1=Thread(target=test1)
    t2=Thread(target=test2)
    t1.start()
    t2.start()
    t1.join()
    t2.join()

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值