zoukankan      html  css  js  c++  java
  • python之线程

    概念

    线程是多任务编程方式之一,可以使用计算机的多核资源。

    线程又称为轻量级的进程,在并发执行上和进程相同。但是一个进程中可以包含多个线程,这些线程共享线程的运行环境。

    线程和进程的比较:

    1 进程的创建开销大,而线程的创建开销小。

    2 进程间的资源共享,只能通过进程间通信。而同一进程下线程间的资源共享,就像使用全局变量一样。

    3 多个功能独立的程序需要成为不同的进程。而不能通过多线程凑成一个进程。

    4 进程空间独立性高,安全性也高,也较少使用同步和互斥方法。而多个线程间因为数据共享,所以同步和互斥几乎是数据必须必须的。

    5 线程也有自己的独立资源,比如说ID,资源集。

    创建线程

    import threading

    t = threading.Thread(target, args, kwargs, name)

    t.name 线程名字

    t.setName() :设置线程名称

    t.getName() : 获取名称

    t.join(n) :主线程阻塞等待分支线程退出,n为超时时间

    t.start() :启动线程

    t.Daemon : daemon属性

    如果在进程中创建了多个线程,当主进程结束时,会根据子进程的daemon属性来来处理不同的情况:

    1 如果某个子线程的daemon为False,那么主线程结束时会检测这个子线程是否结束,如果子线程没有结束,那么主线程会等待子线程运行完后再退出。

    2 如果某个子线程的daemon为True,那么主线程结束时不会对这个子线程进行检查而直接退出,同时daemon为True的子线程将随主线程一起退出,不论它们是否运行完成。

    属性Daemon的默认值为False,如果要设置,必须在调用start()方法启用前。

    t.is_Daemon() :判断Daemon的状态

    t.is_alive() : 判断线程状态

    import threading
    from time import sleep, ctime
    
    # 听歌
    def music(name):
        print('Listen music %s at the %s '%(name, ctime()))
        sleep(2)
    
    # 看书
    def read(name):
        print('Read book %s at the %s'%(name, ctime()))
        sleep(5)
    
    if __name__ == '__main__':
        threads = []
        t1 = threading.Thread(target=music, args=('James',))
        threads.append(t1)
        t2 = threading.Thread(target=read, args=('Wade',))
        threads.append(t2)
    
        # 启动线程
        for t in threads:
            t.start()
    
        # 回收线程
        for t in threads:
            t.join()

    多线程类的创建

    import threading
    from time import sleep, ctime
    
    exitFlag = 0
    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('starting' + self.name)
            print_time(self.name, self.counter, 5)
            print('ending' + self.name)
    
    def print_time(theadName, delay, counter):
        while counter:
            if exitFlag:
                (threading.Thread).exit()
            sleep(delay)
            print("%s at the time:%s"%(theadName, ctime()))
            counter -= 1
    
    if __name__ == '__main__':
        t1 = MyThread(1, 'Mythread-1', 1)
        t2 = MyThread(2, 'Mythread-2', 2)
    
        t1.start()
        t2.start()
    
        t1.join()
        t2.join()
        print('主线程退出!!!')
    View Code
    线程间的通信

    线程间的通信一般是使用全局变量,但是这种方法会带来资源的争夺,所有线程间的共享资源一般需要同步互斥机制。

    所以为了解决这个问题,我们需要使用2种方法。

    方法1: 锁

    lock

    lock = threading.Lock()

    lock.acquire()

    lock.release()

    import threading
    
    a = b = 0
    lock = threading.Lock()
    
    def value():
        while True:
            lock.acquire()
            if a != b:
                print('a = %d, b = %d'%(a, b))
            lock.release()
    
    if __name__ == '__main__':
        t = threading.Thread(target=value)
        t.start()
        while True:
            lock.acquire()
            a += 1
            b += 1
            lock.release()
        t.join()
        '''
        结果是永远也不会发生a!=b,只能在a,b同时修改后读取a,b的值
        '''

    方法2:事件 event

    python事件主要是主线程控制其他线程的执行,主要提供了wait,set,clear方法。

    事件的处理机制:全局定义了一个''Flag'',如果Flag为False,那么当程序执行到event.wait方法就会阻塞,如果Flase为True,那么event.wait方法时将不会阻塞.。

    clear:将Flag定义为False。

    set:将Flag定义为True。

    线程间通信:

    使用event可以让以一个线程等待其他线程的通知,

    e = threading.Event()

    e.set() 设置标志位 设置Flag其为True

    e.wait() 等待设置标志位 等待标志变为True后执行,当为False时候阻塞等待

    e.clear() 清空标志位 设置Flag其为False

    import threading
    import random
    import time
    
    e = threading.Event()
    a = 500
    
    def fun():
        while True:
            time.sleep(2)
            e.wait()
            global a
            print('a = %d'%a)
            a -= random.randint(1, 100)
    
    if __name__ == '__main__':
        t = threading.Thread(target=fun)
        t.start()
    
        while True:
            time.sleep(1)
            a += random.randint(0, 10)
            if a > 100:
                e.set()
            else:
                e.clear()
        t.join()
        '''
        主线程加数字0-10
        子线程减数字0-100
        当数字大于100时,其Flag一直为True,当小于100时,其Flag为Flase,一直阻塞无法打印
        '''
    '''
    只有当判断输入q时,才会改变Flag为False,从而结束子线程循环,结束程序
    '''
    import threading
    import time
    
    class MyThread9(threading.Thread):
    
        def __init__(self):
            threading.Thread.__init__(self)
    
        def run(self):
            global event
            while True:
                if event.isSet():
                    print(self.getName() + ' is Running!')
                    time.sleep(2)
                else:
                    print(self.getName() + ' Stop!!')
                    break
    
    event = threading.Event()
    event.set()
    
    def func():
        t1 = []
        t1.append(MyThread9())
    
        for i in t1:
            i.start()
        time.sleep(10)
        q = input('请输入退出:')
        if q == 'q':
            event.clear()
        for i in t1:
            i.join()
        print('all over!!!')
    if __name__ == '__main__':
        func() 
  • 相关阅读:
    Tomcat6 一些调优设置内存和连接数
    【原创】使用c3p0数据库连接池时出现com.mchange.v2.resourcepool.TimeoutException
    JVM内存的设置
    JBOSS以及tomcat最大连接数配置和jvm内存配置
    摘抄python __init__
    Python中__init__方法介绍
    Python 绝对简明手册
    python中eval, exec, execfile,和compile [转载]
    extern、static、auto、register 定义变量的不同用法
    Python 网络编程说明
  • 原文地址:https://www.cnblogs.com/xiaozx/p/10781106.html
Copyright © 2011-2022 走看看