Python基础---线程

调用方式

python的线程调用有两种方式。一种是直接调用,一种是继承式调用

直接调用

import threading,time

#方法一
def run(n):

    print(n)
    time.sleep(2)
t1 = threading.Thread(target=run,args=("t1",))
t2 = threading.Thread(target=run,args=("t2",))
t1.start()
t2.start()
使用类的方法调用
#方法二(使用类的方法)
import threading,time
class MyThread(threading.Thread):
    def __init__(self,n):
        super(MyThread,self).__init__()
        self.n = n

    def run(self):     #函数名必须为run
        print(self.n)
        time.sleep(2)

t1 = MyThread(1)
t2 = MyThread(2)

t1.start()
t2.start()


join和Daemon

join()等待线程结束后再往后继续运行

Daemon()守护线程

使用setDaemon(True)那么主线程不会等待子线程结束才结束,主线程结束后子线程也会直接结束,必须要在start之前设置否则会报错

python中默认为setDaemon(False),主线程结束了子线程依然会执行直到完毕。

join例子:

import threading,time
class MyThread(threading.Thread):
    def __init__(self,n):
        super(MyThread,self).__init__()
        self.n = n

    def run(self):     #函数名必须为run
        print(self.n)
        time.sleep(2)
        print('end')

t1 = MyThread('t1')
t2 = MyThread('t2')
t1.start()
t1.join()
t2.start()
t2.join()
结果


setDaemon()例子

import threading,time
class MyThread(threading.Thread):
    def __init__(self,n):
        super(MyThread,self).__init__()
        self.n = n

    def run(self):     #函数名必须为run
        print(self.n)
        time.sleep(2)
        print('end')

t1 = MyThread('t1')
t2 = MyThread('t2')
t1.setDaemon(True)
t2.setDaemon(True)
t1.start()
t2.start()

结果



线程锁

子线程可以共享父线程的内存空间,当存在多个子线程需要同时修改一个数据的时候就可能出现问题
假设两个子线程执行的操作都是num+1,由于线程是同时执行的,第一个子线程先取num = 1 ,第二个线程有取出num依然为1,线程一结束后num更改为2,随之线程二结束num依然被改为2,就与我们的目标出现冲突,这个时候就需要用到线程锁了,当线程一访问num的时候线程二是无法访问num的,线程一结束后释放num线程二才能访问num,这就使得num的结果不会产生冲突了。
#线程锁示例
import threading

num = 0
t_objs = []
lock = threading.Lock()

def run():
    lock.acquire()  #加锁
    global num      #声明全局变量
    num += 1        #执行加一操作
    lock.release()  #释放锁

for i in range(500):
    t = threading.Thread(target=run)
    t.start()
    t_objs.append(t)

for t in t_objs:    #等待所有线程结束
    t.join()

print(num)
递归锁则是在一个锁里面又嵌套另外一个线程锁
#递归锁
import threading

def run1():
    lock.acquire()
    global num
    num += 1
    lock.release()
    return num

def run2():
    lock.acquire()
    global num2
    num2 += 1
    lock.release()
    return num2

def run3():
    lock.acquire()
    res = run1()
    res2 = run2()
    lock.release()
    print(res, res2)

if __name__ == '__main__':

    num, num2 = 0, 0
    lock = threading.RLock()
    for i in range(10):
        t = threading.Thread(target=run3)
        t.start()
结果


信号量(Semaphore)

线程锁每次只允许一个线程操作数据,Semaphore则可同时允许多个线程操作,当达到允许的最大值的时候后面的则需要等待,前面的线程执行完毕后才可执行,因此操作同一个数据的时候依然有可能出错
#信号量

import threading,time

def run(num):
    semaphore.acquire()
    time.sleep(1)
    print(num)
    semaphore.release()

semaphore = threading.BoundedSemaphore(3) #最多运行三个线程
for i in range(10):
    t = threading.Thread(target=run,args=(i,))
    t.start()

事件(Event)

Event默认内置了一个标志,初始值为False
event总共就四中方法:set()、clear()、wait()、is_set()
set()设置标志位为True
clear()设置标志位为False
wait()等待标志位设为True
is_set()判断标志位是否被设为True

已红绿灯为例说明,首先写出交通灯,event.clear()相当于红灯,event.set()相当于绿灯,红灯为5秒绿灯也为5秒,用count来计数,当count超过10的时候重置count,这样红绿灯就能以5秒为间隔循环运行
import time,threading

event = threading.Event()

def light():
    count = 0
    while True:
        if count >= 5 and count < 10:
            event.clear()     #相当于红灯了
            print("red light please wait...")
        elif count > 10 :
            event.set()       #相当于绿灯
            count = 0        
        else:
            print("go go go ...")
        time.sleep(1)
        count += 1
再来写car
def car():
    while True:
        if event.is_set():  #判断event是否被set,相当于检测是否为绿灯
            print('run...')
            time.sleep(1)
        else:
            print('waiting for green light..')
            event.wait()
            print('green light is on go...')
运行
l = threading.Thread(target=light)
c = threading.Thread(target=car)
l.start()
c.start()
最终的结果



努力成为一名GEEK!
原文地址:https://www.cnblogs.com/FanMLei/p/10501032.html