python高级编程——线程和线程池

线程模块
          线程的特点:
               本质上是异步的、需要多个并发活动、每个活动的处理顺序可能是不确定的、或者说是随机的,不可预测的,宏观上是同时运行的
     
          进程与线程的关系:
               多任务可以由多进程完成,也可以由一个进程内的多线程完成,进程有若干个线程组成,一个进程至少有一个线程。在使用线程的过程中一般建议使用threading模块,相比于_thread高级一些。很多地方线程和进程是一样的
          
          threading模块的Thread类:
               属性: name ------>名字
                         ident ------->线程标识符
                         daemon ------->守护线程的标识,类型bool
               方法:__init__构造函数,和进程的构造函数差不多,可以参考进程的构造函数
                         start:线程启动
                         run:定义线程功能方法,一般是在子类重新定义的
                         join:在启动线程终止前一直挂起,timeout是阻塞时间
 
使用Thread类创建线程的三种方法:(直接看实例)
          ①创建Thread类实例,传给他一个函数
# 1、创建Thread类实例,传给它一个函数
# 线程的属性和方法
def task(task_id, task_time):
    print("start task", task_id, "at", ctime())
    sleep(task_time)
    print("task", task_id, "done at", ctime())


if __name__ == "__main__":
    print("准备创建线程")
    # 创建Thread类实例,传给它一个函数,传参也是关键字参数
    t = threading.Thread(target=task, args=(1, 2))
    print("准备启动线程")
    # 两种设置守护线程的方式,
    # 守护线程和守护进程就是主进程运行完,守护进(线)程立刻结束
    # t.setDaemon(True)
    t.daemon = True
    t.start()
    # 名字以Thread-N起名,N从1开始
    print("线程的名字:", t.name)
    print("线程的id:", t.ident)
    print("线程已经启动")

 

  ②创建Thread的实例,传给他一个可调用的实例化对象
# 2、创建Thread的实例,传给他一个可调用的类的实例化对象
# 重写方法__call__
def task(task_id, task_time):
    print("start task", task_id, "at", ctime())
    sleep(task_time)
    print("task", task_id, "done at", ctime())


# 创建一个简单的类
class ThreadFunc(object):
    def __init__(self, *args):
        super().__init__()
        self.args = args

    # __call__功能是使得实例化对象也可以调用
    def __call__(self, *args, **kwargs):
        task(*self.args)


if __name__ == "__main__":
    t = threading.Thread(target=ThreadFunc(1, 2))
    t.start()
    t.join()

 

  ③派生Thread的子类,并创建子类的实例(推荐)

# 3、派生Thread的子类,并创建子类的实例(推荐)
def task(task_id, task_time):
    print("start task", task_id, "at", ctime())
    sleep(task_time)
    print("task", task_id, "done at", ctime())


class MyThread(threading.Thread):
    def __init__(self, *args):
        super().__init__()
        self.args = args

    def run(self):
        task(*self.args)


if __name__ == "__main__":
    myThread = MyThread(1, 2)
    # 这里不是调用run方法,和进程的使用差别不大
    myThread.start()
    myThread.join()

 

          线程的状态(一般是简化之后的)
                1. 新建(NEW):新创建了一个线程对象。
                2. 可运行(RUNNABLE):线程对象创建后,其他线程(比如main线程)调用 了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调 度选中,获取cpu 的使用权 。 
                3. 运行(RUNNING):可运行状态(runnable)的线程获得了cpu 时间片( timeslice) ,执行程序代码。
                4. 阻塞(BLOCKED):阻塞状态是指线程因为某种原因放弃了cpu 使用权,也 即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状 态,才有机会再次获得cpu timeslice 转到运行(running)状态。阻塞的情况 分三种:
        (一). 等待阻塞:sleep
        (二). 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线 程占用。
               5. 死亡(DEAD):线程run()、main() 方法执行结束,或者因异常退出了run() 方法,则该线程结束生命周期。死亡的线程不可再次复生。
 
 
               状态图切换:

 

  总结:在一个进程的多个线程是可以共享进程的全局变量的,但是多个线程若同时修改这个全局变量,就可能造成多个线程之间对全局变量的混乱(即线程是不安全的)下一篇就是就要讲到锁机制了。

 
 
 
 
 
posted @ 2019-08-29 18:34  xsha_h  阅读(344)  评论(0编辑  收藏  举报