python 多线程与多进程
一 线程的概念与描述
并行运行这些相互独立的多任务,因此提出了多线程编程的概念,主线程应该是个线程的管理者,应该知道子线程的工作,以便于管理
正是由于全局锁的关系,使得线程只能够一个个的取访问,也就是python是假的多线程,但是正式这种特性使得它更适合io密集型的操作,比如互联网文件的存取
''' import threading 模块 th=threading.Thread(target=函数名) 创建一个线程,线程的命名空间为函数内 th.start() 开启线程 th.join() 表示线程等待,默认的永久等待. th.getName() 表示获取线程的名字 th.ident() 表示获取id地址(硬件) len(threading.enumerate()) 查看线程的数量 '''
多线程共享全局变量,有注意多线程可能会产生资源的抢占问题。可以通过全局锁来解决这个问题
''' nux=Threading.LOCK() 直接将线程锁当做参数,传递给创建线程的函数 nux.acquire() 开启锁,将全局变量要修改的部分进行锁定。 nux.release() 关闭锁,让其以的线程可以进行全局变量的修改
threading.Thread(target=函数名,args=(nux,)) 向函数传递值 '''
线程锁代码实例:
import threading import time g_num = 0 def test1(num): global g_num for i in range(num): mutex.acquire() # 上锁 g_num += 1 mutex.release() # 解锁 print("---test1---g_num=%d"%g_num) def test2(num): global g_num for i in range(num): mutex.acquire() # 上锁 g_num += 1 mutex.release() # 解锁 print("---test2---g_num=%d"%g_num) # 创建一个互斥锁 # 默认是未上锁的状态 mutex = threading.Lock() # 创建2个线程,让他们各自对g_num加1000000次 p1 = threading.Thread(target=test1, args=(1000000,)) p1.start() p2 = threading.Thread(target=test2, args=(1000000,)) p2.start() # 等待计算完成 while len(threading.enumerate()) != 1: time.sleep(1) print("2个线程对同一个全局变量操作之后的最终结果是:%s" % g_num)
线程锁:当有竞争的时候,可以设置一个线程锁,线程锁是当线程竞争资源的时候,谁先触发线程锁,就会将全局变量进行创建临界区,锁住允许第一个获得锁的线程进入临街区,并执行代码。等待线程的执行完毕
线程的优缺点:
1,多进程的优点是创建的进程需要的资源大
2,多线程的缺点是由于所有的线程共享资源,一个线程死亡,整个进程就会崩溃
3,多进程与多线程数量越多就会越消耗资源。因为连续的切换作用
4,异步指的是异步io操作,io操作,与cpu操作能够随时切换,就像异步一样。
不过我们平时很少使用多线程,多进程外加协程。
二 进程:
1,进程是系统分配资源的最小单位,线程是程序执行的最小单位。
2,进程之间是无序的,与操作系统的调度策略有关
3创建子进程的过程就会对父进程的代码进行复制。线程之间的通信,可以通过Queue 队列类来进行通信
4,多少个进程有几个cpu ,8个核有8个进程,当你开启16个进程,还是争夺8个cpu 。不能达到16个并行,是并行和并发一起抢夺资源.
5,一个进程最多打开课1024个文件
''' from multiprocessing import Process,Queue pro=Process(target='函数名',args=(q,)) 通过元组进行传参,创建一个进程函数,将队列传进去 pro.start() 开启进程 pro.join() 表示进程等待,参数是等待时间,超过时间就会执行下面的代码。 pro.is_alive() 表示进程的子进程是否存活 pro.terminate() 不管进程程是否存在,进行终止进程的操作,有操作系统来完成,有一定的时间延迟 os.getpid() 返回当前进程的进程号! os 与进程相互使用, os.getppid() 返回父进程的进程号 q=Queue(3) #初始化一个队列 q.put('1') 向队列里面进行传参数 q.full() 如果返回为True 表示队列已经满了,不会抛异常,只会等待 q.name 表示返回进程的名字 q.empty() 表示队列是否为空 q.get() 得到变量,先进先出 '''
队列的用法实例:
#coding=utf-8 from multiprocessing import Queue q=Queue(3) #初始化一个Queue对象,最多可接收三条put消息 q.put("消息1") q.put("消息2") print(q.full()) #False q.put("消息3") print(q.full()) #True #因为消息列队已满下面的try都会抛出异常,第一个try会等待2秒后再抛出异常,第二个Try会立刻抛出异常 try: q.put("消息4",True,2) except: print("消息列队已满,现有消息数量:%s"%q.qsize()) try: q.put_nowait("消息4") except: print("消息列队已满,现有消息数量:%s"%q.qsize()) #推荐的方式,先判断消息列队是否已满,再写入 if not q.full(): q.put_nowait("消息4") #读取消息时,先判断消息列队是否为空,再读取 if not q.empty(): for i in range(q.qsize()): print(q.get_nowait())
进程通过队列来通信实例:
from multiprocessing import Process, Queue import os, time, random # 写数据进程执行的代码: def write(q): for value in ['A', 'B', 'C']: print('Put %s to queue...' % value) q.put(value) time.sleep(random.random()) # 读数据进程执行的代码: def read(q): while True: if not q.empty(): #Queue.get([block[, timeout]]):获取队列中的一条消息,然后将其从列队中移除,block默认值为True value = q.get(True) print('Get %s from queue.' % value) time.sleep(random.random()) else: break if __name__=='__main__': # 父进程创建Queue,并传给各个子进程: q = Queue() pw = Process(target=write, args=(q,)) pr = Process(target=read, args=(q,)) # 启动子进程pw,写入: pw.start() # 等待pw结束: pw.join() # 启动子进程pr,读取: pr.start() pr.join() # pr进程里是死循环,无法等待其结束,只能强行终止: print('') print('所有数据都写入并且读完')