Python学习-线程
1.方法
run(): 用以表示线程活动的方法。
start():启动线程活动。
join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
isAlive(): 返回线程是否活动的。
getName(): 返回线程名。
setName(): 设置线程名。
2.创建线程的两种方式
继承式
import threading # 导入库
class Thread_ (threading.Thread):
def __init__(self, n):
threading.Thread.__init__(self) #重写父类方法
self.num = n
def run(self):
print(self.num)
if __name__ == "__main__":
a = Thread_(2) # 开启一个线程
a.start() # 启动线程
面向对象式
def Test(i):
print('开始测试%d'%i)
time.sleep(1)
print('测试结束')
if __name__=='__main__':
#多线程
for i in range(5):#利用循环创建5个线程
t=threading.Thread(target=Test,args=(i,)) # 使用线程类驱动函数,args为参数,没有可以不写,但是这样并不能够对run方法自定义,有一定的局限性
#启动线程
t.start()
3.多线程
为了展示同一个程序是否使用多线程的效果,我们进行对比,
未使用多线程
import time
import random
import threading
lists = ['python', 'django', 'java',
'flask', 'perl', 'C sharp', 'hadoop'
]
new_lists = []
def work():
if len(lists) == 0:
return
data = random.choice(lists)
lists.remove(data)
new_data = '%s_new' % data
new_lists.append(new_data)
time.sleep(1)
if __name__ == '__main__':
start = time.time()
for i in range(len(lists)):
work()
print('old list:', lists)
print('new list:', new_lists)
print('time is %s' % (time.time() - start))
使用多线程
import time
import random
import threading
lists = ['python', 'django', 'java',
'flask', 'perl', 'C sharp', 'hadoop'
]
new_lists = []
def work():
if len(lists) == 0:
return
data = random.choice(lists)
lists.remove(data)
new_data = '%s_new' % data
new_lists.append(new_data)
time.sleep(1)
if __name__ == '__main__':
start = time.time()
# print('old list len:', len(lists))
t_list = []
for i in range(len(lists)):
t = threading.Thread(target=work)
t_list.append(t)
t.start()
for t in t_list:
t.join()
print('old list:', lists)
print('new list:', new_lists)
# print('new_list len', len(new_lists))
print('time is %s' % (time.time() - start))
4.线程同步
多线程实现同步有四种方式:
锁机制,信号量,条件判断和同步队列,这部分我主要写的是锁机制。
锁机制:如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步。
使用 Thread 对象的 Lock 和 Rlock 可以实现简单的线程同步,这两个对象都有 acquire 方法和 release 方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到 acquire 和 release 方法之间。
4.1.普通锁同步
普通锁同步
class myThread(threading.Thread):
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
def run(self):
print("Start " + self.name)
# 获得锁,成功获得锁定后返回True
# 可选的timeout参数不填时将一直阻塞直到获得锁定
# 否则超时后将返回False
threadLock.acquire()
print_time(self.name, self.counter, 5)
# 释放锁
threadLock.release()
def print_time(threadName, delay, counter):
while counter:
time.sleep(delay)
print("%s: %s" %(threadName, time.ctime(time.time())))
counter -= 1
threadLock = threading.Lock()
threads = []
# 创建新线程
thread1 = myThread(1, "Thread_1", 1)
thread2 = myThread(2, "Thread_2", 2)
# 开启新线程
thread1.start()
thread2.start()
# 添加线程到线程列表
threads.append(thread1)
threads.append(thread2)
# 等待所有线程完成
for t in threads:
t.join()
print("Exit")
4.2.递归锁
RLock(可重入锁)是一个可以被同一个线程请求多次的同步指令。RLock使用了“拥有的线程”和“递归等级”的概念,处于锁定状态时,RLock被某个线程拥有。拥有RLock的线程可以再次调用acquire(),释放锁时需要调用release()相同次数。可以认为RLock包含一个锁定池和一个初始值为0的计数器,每次成功调用 acquire()/release(),计数器将+1/-1,为0时锁处于未锁定状态。
构造方法:mylock = Threading.RLock()
递归锁同步
import threading
mylock = threading.RLock()
num = 0
class Thread(threading.Thread):
def __init__(self, name):
threading.Thread.__init__(self)
self.t_name = name
def run(self):
global num
while True:
mylock.acquire()
print('\n%s locked, number: %d' % (self.t_name, num))
if num >= 3:
mylock.release()
print('\n%s released, number: %d' % (self.t_name, num))
break
num += 1
print('\n%s released, number: %d' % (self.t_name, num))
mylock.release()
def test():
thread1 = Thread('A')
thread2 = Thread('B')
thread1.start()
thread2.start()
if __name__ == '__main__':
test()
A locked, number: 0
A released, number: 1
A locked, number: 1
A released, number: 2
A locked, number: 2
A released, number: 3
A locked, number: 3
A released, number: 3
B locked, number: 3
B released, number: 3
5.线程池
一个线程的运行时间可以分为3部分:线程的启动时间、线程体的运行时间和线程的销毁时间。在多线程处理的情景中,如果线程不能被重用,就意味着每次创建都需要经过启动、销毁和运行3个过程。这会增加系统相应的时间,降低了效率。使用线程池处理,处理当前任务之后并不销毁而是被安排处理下一个任务,能够避免多次创建线程,从而节省线程创建和销毁的开销,能带来更好的性能和系统稳定性。
方法:
futures.ThreadPoolExecutor:创建线程池
submit():往线程池中加任务
done():线程池中的某个线程是否完成了任务
result():获取当前线程执行任务的结果
普通线程池
# coding:utf-8
import time
import os
import threading
from concurrent.futures import ThreadPoolExecutor
def work(i):
print(i)
time.sleep(1)
if __name__ == '__main__':
t = ThreadPoolExecutor(2)
for i in range(10):
t.submit(work, (i, ))
(4,)(5,)
(6,)(7,)
(8,)(9,)
带有同步锁的线程池
import time
import os
import threading
from concurrent.futures import ThreadPoolExecutor
lock = threading.Lock()
def work(i):
lock.acquire()
print(i)
time.sleep(1)
lock.release()
# return 'result %s' % i
if __name__ == '__main__':
t = ThreadPoolExecutor(2)
for i in range(10):
t.submit(work, (i, ))
6.线程守护
有一种线程,它是在后台运行的,它的任务是为其他线程提供服务,这种线程被称为“后台线程(Daemon Thread)”,又称为“守护线程”或“精灵线程”。Python 解释器的垃圾回收线程就是典型的后台线程。如果所有的前台线程都死亡了,那么后台线程会自动死亡。
线程守护
def action(max):
for i in range(max):
print(threading.current_thread().name + " " + str(i))
t = threading.Thread(target=action, args=(10,), name='后台线程')
# 将此线程设置成后台线程
# 也可在创建Thread对象时通过daemon参数将其设为后台线程
t.setDaemon = True # 这一步很关键,必须在start()之前设置,否则报错
# 启动后台线程
t.start()
for i in range(10):
print(threading.current_thread().name + " " + str(i))
本文来自博客园,作者:Ancientswar,转载请注明原文链接:https://www.cnblogs.com/ancientswar/p/16478858.html

浙公网安备 33010602011771号