线程创建
python3推荐使用threading模块来实现线程,这个模块创建线程有两种方法;一种是,自定义一个类继承threading,该类的对象有threading类的方法和属性可以执行作为线程运行;另一种,直接使用threading类,用线程函数、参数初始化threading对象。两种方法各有利弊,按个人习惯选取即可。
示例如下:
#!/usr/bin/python3
import sys
import threading
from time import sleep
def threading_demo_fun1():
# 线程执行函数
def threading_entry(a, b, arg1, arg2):
print('thread name:{0} start. kwargs={1}, {2}'.format(threading.current_thread().name, arg1, arg2))
print('args a:{0} b:{1}'.format(a, b))
print('thread name:{0} name:{1}'.format(threading.current_thread().name, threading.current_thread()))
sleep(1)
print('thread pid:{0} finish.'.format(threading.current_thread().name))
# threading使用方法一:
# 使用threading.Thread对象直接实例化线程,参数通过args和kwargs传递
# target:要跑的线程函数
# name:线程名,可以在线程函数中用threading.current_thread().name获得
# args:以序列的方式的参数
threads = []
for i in range(0, 1):
threads.append(threading.Thread(target=threading_entry, name='mythread-%s' % i, args=(123, 456,),
kwargs={'arg1': i, 'arg2': 2}))
# 设定守护线程: 如True 主退出后,子还在执行; 否则(默认即为False), 主退出后子跟着退出
# threads[i].setDaemon(True)
threads[i].start()
for t in threads:
t.join()
# 方法二: 先创建自己的类并继承threading.Thread
# 比较麻烦,不怎么好用
class Mythread(threading.Thread):
def __init__(self, threadid, threadname, threadarg1, threadarg2):
threading.Thread.__init__(self)
# 下面将参数记录到对象内
self.threadid = threadid
self.threadname = threadname
self.threadarg1 = threadarg1
self.threadarg2 = threadarg2
def run(self):
print("开始线程name:{0} id:{1}".format(self.threadname, self.threadid))
self.thread_entry(self.threadarg1, self.threadarg2)
print("退出线程name:{0} id:{1}".format(self.threadname, self.threadid))
def thread_entry(self, arg1, arg2):
print('访问类内成员: threadid:{0} threadname:{1}'.format(self.threadid, self.threadname))
print('获取线程入参: arg1:{0} arg2:{1}'.format(arg1, arg2))
sleep(1)
if __name__ == '__main__':
# threading方法一
print('threading方法一:')
threading_demo_fun1()
print('threading方法二:')
mythread = Mythread(0x4500, 'MythreadClass-thread-1', 250, 'Hello threading')
mythread.start()
mythread.join()
需要注意参数传递的方式。
方法一,直接使用threading对象创建线程,在构造函数中传送参数。直接写参数会按顺序传递到线程函数中,也可以使用字典键值对的方式指定参数名来传递。
方法二,继承的方式创建自定义threading对象,在自定义类的构造函数中传递参数,init函数中可以直接将用户的参数传递给自己的self,py会自动为该类创建属性,我们在线程函数中直接当类成员属性调用即可。
另外,python的多线程(这里只讨论使用threading)本质上不能实现真正的多线程,大致原因是python解释器在线程执行时会有个拿锁的过程,这会导致python(包括3.x)在执行多线程时跑不满多核心CPU,要想解决这个方法只能更换解释器,这个不在本文讨论内。
线程安全
虽然本质上python解析器只能单线程执行,但线程执行过程中遇到IO调用、执行一定指令数后会被解释器休眠让出cpu给其他线程执行,在此期间会和多线程编程一样存在线程数据安全问题。threading线程提供线程锁来解决这个问题。
#!/usr/bin/python
import threading
def threading_entry(mstring1, mstring2):
while True:
MyLock.acquire()
print("thread name:{0} str:{1}".format(threading.current_thread().name, mstring1))
print("thread name:{0} str:{1}".format(threading.current_thread().name, mstring2))
MyLock.release()
MyLock = threading.Lock()
if __name__ == "__main__":
threads = []
for i in range(0, 10):
threads.append(threading.Thread(target=threading_entry, name='mythread-%s' % i, args=("123", "456",)))
threads[i].start()
for t in threads:
t.join()
部分执行结果:
thread name:mythread-8 str:456
thread name:mythread-8 str:123
thread name:mythread-8 str:456
thread name:mythread-8 str:123
thread name:mythread-8 str:456
thread name:mythread-8 str:123
thread name:mythread-8 str:456
thread name:mythread-8 str:123
thread name:mythread-8 str:456
thread name:mythread-8 str:123
此时如果去掉线程函数中的锁,执行结果将为:
thread name:mythread-5 str:123
thread name:mythread-8 str:456
thread name:mythread-3 str:123
thread name:mythread-9 str:123
thread name:mythread-1 str:456
thread name:mythread-1 str:123thread name:mythread-8 str:123
thread name:mythread-8 str:456thread name:mythread-3 str:456
不同线程的print语句出现了交叉,而线程锁可以保证。
线程优先级队列( Queue)
continue。。。。