线程创建

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。。。。