Python多线程_thread和Threading

目录

多线程

_thread模块

使用 _thread模块创建线程

threading

使用 threading模块创建线程

线程同步 


Python3通过两个标准库 _thread threading 提供对线程的支持。

_thread 提供了低级别的、原始的线程以及一个简单的锁,它相比于 threading 模块的功能还是比较有限的。threading 模块除了包含 _thread 模块中的所有方法外,还提供的其他方法

多线程

多线程类似于同时执行多个不同程序,多线程运行有如下优点:

  • 使用线程可以把占据长时间的程序中的任务放到后台去处理。
  • 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
  • 程序的运行速度可能加快
  • 在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。

线程在执行过程中与进程还是有区别的。每个独立的进程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

扫描二维码关注公众号,回复: 3920977 查看本文章

每个线程都有他自己的一组CPU寄存器,称为线程的上下文,该上下文反映了线程上次运行该线程的CPU寄存器的状态。

  • 线程可以被抢占(中断)。
  • 在其他线程正在运行时,线程可以暂时搁置(也称为睡眠) -- 这就是线程的退让

Python中使用线程有两种方式函数 或者用 来包装线程对象。_thread 模块用的是函数式线程,threading 可以包装线程对象,也可以使用函数式线程

_thread模块

函数式:调用 _thread 模块中的 start_new_thread() 函数来产生新线程。语法如下:

_thread.start_new_thread ( function, args[, kwargs] )

参数说明:

  • function - 线程函数
  • args - 传递给线程函数的参数,他必须是个 tuple 类型
  • kwargs - 可选参数

使用 _thread模块创建线程

import _thread
import time
from datetime import datetime

def Test(name):
    for i in range(3):
        print(name,datetime.now())
        time.sleep(1)
def main():
    try:
        _thread.start_new_thread(Test,("thread-1:",))
        _thread.start_new_thread(Test,("thread-2:",))
    except Exception as e:
        print("异常对象的类型是:%s"%type(e))
        print("异常对象的内容是:%s"%e)

if __name__=='__main__':
    main()
############################################################
thread-1: 2018-11-02 16:53:55.280406
thread-2: 2018-11-02 16:53:55.288425
thread-1: 2018-11-02 16:53:56.289226
thread-2: 2018-11-02 16:53:56.296242
thread-1: 2018-11-02 16:53:57.290821
thread-2: 2018-11-02 16:53:57.297959

threading

threading 模块除了包含 _thread 模块中的所有方法外,还提供其他方法:

  • threading.currentThread():  返回当前的线程变量。
  • threading.enumerate():  返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前。
  • threading.activeCount(): 返回正在运行的线程数量,与 len(threading.enumerate()) 有相同的结果。

除了使用方法外,threading线程模块同样提供了 threading.Thread 类来处理线程,threading.Thread类提供了以下方法:

  • run(): 用以表示线程活动的方法。
  • start():启动线程活动。
  • join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止:正常退出或者抛出未处理的异常,或者是可选的超时发生。
  • isAlive(): 返回线程是否活动的。
  • getName(): 返回线程名。
  • setName(): 设置线程名。

使用 threading模块创建线程

我们可以通过创建一个子类继承于 threading.Thread ,并实例化后调用 start() 方法启动新线程,即它调用了线程的 run() 方法:

import threading
import time
from datetime import datetime

class myThread(threading.Thread):
    def __init__(self,name):
        threading.Thread.__init__(self)
        self.name=name
    def run(self):
        print ("开始线程:" + self.name)
        for i in range(3):
            print(self.name,datetime.now())
            time.sleep(1)
        print ("退出线程:" + self.name)

thread1=myThread("Thread-1")
thread2=myThread("Thread-2")

try:
    thread1.start()           #启动线程,代用了该线程的 run() 方法
    thread2.start()
except Exception as e:
    print("异常对象的类型是:%s"%type(e))
    print("异常对象的内容是:%s"%e)
###########################################
开始线程:Thread-1
Thread-1 2018-11-02 17:13:12.633523
开始线程:Thread-2
Thread-2 2018-11-02 17:13:12.640547
Thread-1 2018-11-02 17:13:13.635327
Thread-2 2018-11-02 17:13:13.641349
Thread-1 2018-11-02 17:13:14.637005
Thread-2 2018-11-02 17:13:14.642035
退出线程:Thread-1
退出线程:Thread-2

我们也可以使用函数来创建线程 

import threading
import time
from datetime import datetime

def Test(name):
    for i in range(3):
        print(name,datetime.now())
        time.sleep(1)
def main():
    try:
        t1=threading.Thread(target=Test,args=("thread-1:",))  #调用threading.Thread函数,target参数是要执行的韩三户,args是要传入的参数,为元组类型
        t2=threading.Thread(target=Test,args=("thread-2:",))
        t1.start()        #启动线程
        t2.start()
    except Exception as e:
        print("异常对象的类型是:%s"%type(e))
        print("异常对象的内容是:%s"%e)

if __name__=='__main__':
    main()
##########################################################
thread-1: 2018-11-03 16:14:05.278748
thread-2: 2018-11-03 16:14:05.288774
thread-1: 2018-11-03 16:14:06.289436
thread-2: 2018-11-03 16:14:06.300462
thread-1: 2018-11-03 16:14:07.290130
thread-2: 2018-11-03 16:14:07.302127

线程同步 

如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步。

使用 threading 对象的 LockRlock 可以实现简单的线程同步,这两个对象都有 acquire() 方法和 release() 方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到 acquire() 和 release() 方法之间。如下:

多线程的优势在于可以同时运行多个任务(至少感觉起来是这样)。但是当线程需要共享数据时,可能存在数据不同步的问题。

考虑这样一种情况:

一个列表里所有元素都是0,线程"set"从后向前把所有元素改成1,而线程"print"负责从前往后读取列表并打印。

那么,可能线程"set"开始改的时候,线程"print"便来打印列表了,输出就成了一半0一半1,这就是数据的不同步。为了避免这种情况,引入了锁的概念。

锁有两种状态——锁定和未锁定。每当一个线程比如"set"要访问共享数据时,必须先获得锁定;如果已经有别的线程比如"print"获得锁定了,那么就让线程"set"暂停,也就是同步阻塞;等到线程"print"访问完毕,释放锁以后,再让线程"set"继续。

经过这样的处理,打印列表时要么全部输出0,要么全部输出1,不会再出现一半0一半1的尴尬场面。

实例:

import threading
import time
from datetime import datetime

threadLock=threading.Lock()  #得到一个threadLock对象

class myThread(threading.Thread):
    def __init__(self,name):
        threading.Thread.__init__(self)
        self.name=name
    def run(self):
        print ("*********"+"开始线程:" + self.name+"*********"+"\n")
        threadLock.acquire()       ##获取锁,用于线程同步
        for i in range(3):
            print(self.name,datetime.now())
            time.sleep(1)
        threadLock.release()      #释放锁,开启下一个线程
        print ("*********"+"退出线程:" + self.name+"*********"+"\n")

thread1=myThread("Thread-1")  ##实例化线程对象
thread2=myThread("Thread-2")

def main():
    try: 
        thread1.start()   ##开启新线程
        thread2.start()
        thread1.join()    ##终止线程
        thread2.join()
    except Exception as e:
        print("异常对象的类型是:%s"%type(e))
        print("异常对象的内容是:%s"%e)
if __name__=='__main__':
    main()
##################################################################
*********开始线程:Thread-1*********
*********开始线程:Thread-2*********

Thread-1 2018-11-02 19:12:19.804318

Thread-1 2018-11-02 19:12:20.805980
Thread-1 2018-11-02 19:12:21.807641
*********退出线程:Thread-1*********
Thread-2 2018-11-02 19:12:22.809306

Thread-2 2018-11-02 19:12:23.809966
Thread-2 2018-11-02 19:12:24.810624
*********退出线程:Thread-2*********

猜你喜欢

转载自blog.csdn.net/qq_36119192/article/details/83656021
今日推荐