python线程
为什么由线程?1,进程的创建,撤销,切换开销比较大。2,由于对称多处理及(SMP)即多cpu的出现,进程并行开销过大。线程,轻量级进程,一个基本的cpu执行单元,程序执行过程中的最小单元,由线程id,程序计数器,寄存器集合,和堆栈共同组成。线程可以与同属于一个进程的其他线程共享进程拥有的资源。线程是属于进程的,线程运行在进程空间内,同一进程所产生的线程共享同一内存空间,当进程退出时该进程所产生的数据被强制删除并退出。在pycharm上运行一段代码并不会开一个进程,所以有时需要守护线程
线程是轻量级进程,一个标准的线程有线程id,当前指令,寄存器集合和堆栈组成,线程是进程的实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有在运行中必不可少的资源,但它可以与同属有一个进程的其他线程共享进程所拥有的全部资源。
使用threading模块创建线程
#coding=utf-8
import threading
import time
def saySorry():
print("亲爱的,我错了,我能吃饭了吗?")
time.sleep(1)
if __name__ == "__main__":
for i in range(5):
t = threading.Thread(target=saySorry)
t.start() #启动线程,即让线程开始执行
多线程并发操作,当调用start()方法后才真正创建线程并执行,每一个线程都有一个唯一的标识符用来区分程序的主次关系,程序主入口被称为主线程,使用threading.Thread()创建的都是子线程,线程数量等于:主线程+子线程数
主线程默认会等待所有子线程结束后再结束
len(threading.enumerate()) 查看线程数量
同时开启几个线程,是没有执行顺序的
t1 = threading.Thread(target=)
t1.setDaemon(True) 设置守护线程
多线程共享全局变量,如果多个线程同时更改同一个全局变量,会造成错误的结果,需要通过t1.join() 让其他线程等待t1线程执行结束再执行,也就相当于没有并发而是并行
互斥锁
murtes = threading.Lock() 使用Lock模块创建线程锁对象
mutes.acquire 锁定同一个进程下不同线程的共享资源,其他线程不能更改此资源
mutes.release() 释放锁
确保了某段关键代码只能由一个线程从头到尾完整地执行
死锁
在线程共享多个资源 时,如果两个线程分别占有一部分资源并同时等待对方的资源,就会造成死锁。
线程的建立
import threading
import time
import os
'''
theading模块建立在_thread模块基础上,thread模块以低级原始的方式处理和控制线程,threading模块对
thread模块进行二次封装,提供了更方便的api处理线程
本代码创建了20个’前台‘线程,然后控制器交给cpu,通过指定算法调度,分片执行指令,
'''
def work(num):
print('in work{}'.format(num))
time.sleep(2)
if __name__ == '__main__':
for i in range(20):
t = threading.Thread(target=work, args=(i,), name='t.{}'.format(i)) # args = 后面必须是元组, name参数设置线程名
t.setDaemon(True) # 在start方法之前设置默认为False,即前台线程,子线程结束后主线程再结束;为True时设置为守护线程,主线程结束,则无论子线程是否执行完毕都结束,即后台线程
t.start()
# t.setName('tt.i') # 设置线程名
# print(t.getName()) # 获取线程名
t.name = 'ttt.{}'.format(i) # t.name设置线程名
print(t.name) # t.name 获取线程名
# print(t.is_alive()) # 判断线程是否是激活状态
# print(t.isAlive()) # 也是判断线程是否是激活状态 后面的括号不能忘!!
print(t.isDaemon()) # 判断是否为守护线程
print(t.ident) # 获取线程的标识符,在本脚本多线程运行的时候,140310960539392线程标示符不同,进程号相同
# t.join() # 逐个执行每个线程,执行完毕后在继续向下执行,此方法让多线程变的毫无意义,线程标识符相同,进程号相同
print(os.getpid()) # 获取进程号,在本脚本多线程,单线程运行时进程号都相同
# t.run() :线程被cpu调度后自动执行线程对象的run方法
# import threading
# import time
#
#
# def worker(num):
# """
# thread worker function
# :return:
# """
# time.sleep(1)
# print("The num is %d" % num)
# return
#
#
# for i in range(20):
# t = threading.Thread(target=worker, args=(i,),name ='t. % d' % i)
# t.start()
线程锁
import threading
import time
'''
由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,CPU接着执行其他线程。
为了保证数据的准确性,引入了锁的概念。所以,可能出现如下问题:
例:假设列表A的所有元素就为0,当一个线程从前向后打印列表的所有元素,
另外一个线程则从后向前修改列表的元素为1,那么输出的时候,列表的元素就会一部分为0,
一部分为1,这就导致了数据的不一致。锁的出现解决了这个问题。
'''
globals_num = 0
lock = threading.RLock()
def Func():
lock.acquire() # 获得锁
global globals_num
globals_num += 1
time.sleep(1)
print(globals_num)
lock.release() # 释放锁
for i in range(10): # 连续创建了十个进程,由于Func方法内有锁,多线程只能一个一个运行
t = threading.Thread(target=Func)
t.start()
线程锁Lock和RLock区别
import threading
import time
'''
由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,CPU接着执行其他线程。为了保证数据的准确性,引入了锁的概念。
RLock允许在同一线程中被多次acquire。而Lock却不允许这种情况。
如果使用RLock,那么acquire和release必须成对出现,即调用了n次acquire,
必须调用n次的release才能真正释放所占用的琐。
'''
# lock = threading.Lock()
# lock.acquire()
# lock.acquire() # 代码在此行产生了死锁
# lock.release()
# lock.release()
# rLock = threading.RLock()
# rLock.acquire()
# rLock.acquire()
# rLock.release()
# rLock.release()
'''下面的代码都计算错误了'''
num = 0
def work(lock):
global num
num += 1
time.sleep(0.5)
# print(num)
def work1(lock):
time.sleep(0.5)
global num
num += 1
if __name__ == '__main__':
lock = threading.Lock()
for i in range(10000):
t = threading.Thread(target=work, args=(lock,))
t1 = threading.Thread(target=work1, args=(lock,))
t.start()
t1.start()
print(num)
import threading
import time
'''
两个线程同时连续修改同一个进程中的同一个全局变量一百万次,运行结束后全局变量被计算错误。
可以使用threading.Lock,acquire上锁,release解锁
'''
def work1(num):
for i in range(num):
global count
count += 1
print('in work1', count)
def work2(num):
for i in range(num):
global count
count += 1
print('in work2', count)
if __name__ == '__main__':
count = 0
num = 10000
t1 = threading.Thread(target=work1, args=(num,))
t2 = threading.Thread(target=work2, args=(num,))
t1.start()
t2.start()
while len(threading.enumerate()) != 1:
time.sleep(0.5)
print(count)
线程Event
import threading
'''
python线程的事件用于主线程控制其他线程的执行,事件主要提供了三个方法 set、wait、clear。
事件处理的机制:全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,那么event.wait 方法时便不再阻塞。
clear:将“Flag”设置为False
set:将“Flag”设置为True
Event.isSet() :判断标识位是否为Ture。
当线程执行的时候,如果flag为False,则线程会阻塞,当flag为True的时候,线程不会阻塞。它提供了本地和远程的并发性。
'''
def do(event):
print('do start')
event.wait()
print('do over')
if __name__ == '__main__':
event_obj = threading.Event()
for i in range(10):
t1 = threading.Thread(target=do, args=(event_obj,))
t1.start()
event_obj.clear()
in_data = input('true?')
if in_data == 'true':
event_obj.set()
自己做一个线程池
# 简单往队列中传输线程数
import threading
import time
import queue
class Threadingpool():
def __init__(self,max_num = 10):
self.queue = queue.Queue(max_num)
for i in range(max_num):
self.queue.put(threading.Thread)
def getthreading(self):
return self.queue.get()
def addthreading(self):
self.queue.put(threading.Thread)
def func(p,i):
time.sleep(1)
print(i)
p.addthreading()
if __name__ == "__main__":
p = Threadingpool()
for i in range(20):
thread = p.getthreading()
t = thread(target = func, args = (p,i))
t.start()
#往队列中无限添加任务
import queue
import threading
import contextlib
import time
StopEvent = object()
class ThreadPool(object):
def __init__(self, max_num):
self.q = queue.Queue()
self.max_num = max_num
self.terminal = False
self.generate_list = []
self.free_list = []
def run(self, func, args, callback=None):
"""
线程池执行一个任务
:param func: 任务函数
:param args: 任务函数所需参数
:param callback: 任务执行失败或成功后执行的回调函数,回调函数有两个参数1、任务函数执行状态;2、任务函数返回值(默认为None,即:不执行回调函数)
:return: 如果线程池已经终止,则返回True否则None
"""
if len(self.free_list) == 0 and len(self.generate_list) < self.max_num:
self.generate_thread()
w = (func, args, callback,)
self.q.put(w)
def generate_thread(self):
"""
创建一个线程
"""
t = threading.Thread(target=self.call)
t.start()
def call(self):
"""
循环去获取任务函数并执行任务函数
"""
current_thread = threading.currentThread
self.generate_list.append(current_thread)
event = self.q.get() # 获取线程
while event != StopEvent: # 判断获取的线程数不等于全局变量
func, arguments, callback = event # 拆分元祖,获得执行函数,参数,回调函数
try:
result = func(*arguments) # 执行函数
status = True
except Exception as e: # 函数执行失败
status = False
result = e
if callback is not None:
try:
callback(status, result)
except Exception as e:
pass
# self.free_list.append(current_thread)
# event = self.q.get()
# self.free_list.remove(current_thread)
with self.work_state():
event = self.q.get()
else:
self.generate_list.remove(current_thread)
def close(self):
"""
关闭线程,给传输全局非元祖的变量来进行关闭
:return:
"""
for i in range(len(self.generate_list)):
self.q.put(StopEvent)
def terminate(self):
"""
突然关闭线程
:return:
"""
self.terminal = True
while self.generate_list:
self.q.put(StopEvent)
self.q.empty()
@contextlib.contextmanager
def work_state(self):
self.free_list.append(threading.currentThread)
try:
yield
finally:
self.free_list.remove(threading.currentThread)
def work(i):
print(i)
return i +1 # 返回给回调函数
def callback(ret):
print(ret)
pool = ThreadPool(10)
for item in range(50):
pool.run(func=work, args=(item,),callback=callback)
pool.terminate()
# pool.close()
https://www.cnblogs.com/serpent/

浙公网安备 33010602011771号