一 线程的概念与描述
并行运行这些相互独立的多任务,因此提出了多线程编程的概念,主线程应该是个线程的管理者,应该知道子线程的工作,以便于管理
正是由于全局锁的关系,使得线程只能够一个个的取访问,也就是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)
View Code
线程锁:当有竞争的时候,可以设置一个线程锁,线程锁是当线程竞争资源的时候,谁先触发线程锁,就会将全局变量进行创建临界区,锁住允许第一个获得锁的线程进入临街区,并执行代码。等待线程的执行完毕
线程的优缺点:
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())
View Code
进程通过队列来通信实例:
![]()
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('所有数据都写入并且读完')
View Code