python多线程-threading

本文深入探讨Python中多线程的使用,包括主线程对子线程的监管、线程间同步机制、条件变量及队列应用。通过实战案例解析线程全局变量的管理与同步控制,帮助读者掌握Python多线程编程技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.主线程对子线程的监管

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@author: ZhongyuanYang
@file: threading_test.py
@time: 2018/9/3 21:32
@desc:测试threading的使用   主线程对子线程的监管
"""
import threading
import time, random

class ThreadDemo(threading.Thread):
    def __init__(self, index, create_time):
        threading.Thread.__init__(self)
        self.index = index
        self.create_time = create_time
        self.local = threading.local()#local数据对象

    def run(self):
        time.sleep(0.1)
        # print (time.time() - self.create_time),'\t', self.index

        print "time_consuming:%d \t index:%d \n" % ((time.time() - self.create_time),self.index)

        print ("Thread %d exit.....\n" % (self.index))
        while 1:#timeout时,每个子线程仍然存活,直到主线程结束,子线程会一同结束;
            i = 0
            i += 1

if __name__ == "__main__":

    threads = []
    for index in range(5):
        thread = ThreadDemo(index, time.time())
        thread.setDaemon(True)#设置后台运行   默认False
        thread.start()
        thread.setName(str(index))#命名
        print"Threading name is %s" % thread.getName()
        threads.append(thread)

        # thread.join(timeout=0.5)

    for thread in threads:
        thread.join(2)#Wait until the thread terminates,阻塞,可设置timeout;
        #join()返回值None,需用isAlive()判断是否超时
        time.sleep(1)
        print("thread_name",thread.getName())

        if not thread.isAlive():# Return whether the thread is alive.
            print "Thread %s timeout" % thread.getName()
            continue

    print "Main thread exit......"

    """总结如下:
    1.join()中的timeout参数设置时间,只有在setDaemon(True)时有效,若setDaemon(False),join(timeout=2)在2s之后任然会阻塞,
    等待子线程的结束。


    2.join(timeout=2)函数在这里只相当于一个“采样”,它不会在超时的时候终止相应thread的执行------超时后,
    "Thread %s timeout" % thread.getName()不会被打印,说明线程并没有结束
    
    超时了的话,isAlive()方法肯定返回的True(因为join()方法不会结束线程,所以线程仍然是活动的)
    
    3.如果某个子线程的daemon属性为False,主线程结束时会检测该子线程是否结束,如果该子线程还在运行,
    则主线程会等待它完成后再退出;

      如果某个子线程的daemon属性为True,主线程运行结束时不对这个子线程进行检查而直接退出
,同时所有daemon值为True的子线程将随主线程一起结束,而不论是否运行完成。
    
    """

2.threading.local() test ---线程全局变量

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@author: ZhongyuanYang
@file: threading_test2.py
@time: 2018/9/4 11:20
@desc:在函数调用的时候,参数传递起来很麻烦,对此,可以使用threading.local()数据对象创建参数变量,这样
一个线程的所有调用到的处理函数都可以  非常方便地访问这些参数变量

而且 local数据对象,其成员变量在每个线程中是相互独立的
"""
'''
ThreadLocal最常用的地方就是为每个线程绑定一个数据库连接,HTTP请求,用户身份信息等,
这样一个线程的所有调用到的处理函数都可以  非常方便地访问这些资源
'''
import threading
import time, random

#----------------------------------------------test1
# 创建全局ThreadLocal对象:
local_school = threading.local()

def process_student():
    print 'Hello, %s (in %s)' % (local_school.student, threading.current_thread().name)

def process_thread(name):
    local_school.student = name#绑定threading.local()数据对象的student,一个线程中的所有
    process_student()

'''
如果不使用threading.local()数据对象,以上两个函数就要如下定义:
def process_student(name):
    print 'Hello, %s (in %s)' % (name, threading.current_thread().name)

def process_thread(name):
    process_student(name)

参数变量 name 传递起来很麻烦,特别是函数调用层次更多的时候
'''

print 'Test1>>>>>>>>>>>>>>>>>>>>>>>>>>start'

threads = []
for i in range(20):
    thread = threading.Thread(target= process_thread, args=('Bob-%s' % i,), name='Thread-%s' % i)
    thread.start()
    threads.append(thread)

for thread in threads:
    thread.join()
print 'Test1>>>>>>>>>>>>>>>>>>>>>>>>>>end'

'''
全局变量local_school就是一个ThreadLocal对象,每个Thread对它都可以读写student属性,但互不影响。
你可以把local_school看成全局变量,但每个属性如local_school.student都是线程的局部变量,
可以任意读写而互不干扰,也不用管理锁的问题,ThreadLocal内部会处理。
'''

#----------------------------------------------test2
class ThreadLocal(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.local = threading.local()  # local数据对象,其成员变量在每个线程中是相互独立的

        '''经测试,self.number,self.local.number,number产生效果一致,每个线程中的这些变量相互独立,
        并不会相互影响,对于local()类的作用还需进一步探索----------见test1'''
        self.number = []

    def run(self):

        time.sleep(random.random())  # 0-1随机
        self.local.number = []
        number = []
        for i in range(5):
            self.local.number.append(random.choice(range(10)))
            self.number.append(random.choice(range(10)))

        time.sleep(2.0)

        # print(threading.currentThread(), self.local.number)
        print(threading.currentThread(), self.number)

if __name__ == "__main__":

    print 'Test2>>>>>>>>>>>>>>>>>>>>>>>>>>start'
    print(threading.currentThread())#Return the current Thread object, corresponding to the caller's thread of control.

    threads = []
    for i in range(10):
        thread = ThreadLocal()
        thread.start()
        threads.append(thread)

    for i in range(10):
        threads[i].join()

    print('Test2>>>>>>>>>>>>>>>>>>>>>>>>>>end')


3.线程之间的同步-----锁机制

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@author: ZhongyuanYang
@file: threading_同步test1.py
@time: 2018/9/5 10:13
@desc:测试线程之间的同步-----锁机制
"""
'''结果表明:若不加 锁机制,100个线程运行到最后,value值<100'''

import threading
import time, random

class Counter():
    """计数器"""
    def __init__(self):
        self.value = 0
        self.lock = threading.Lock()#生成 锁


    def increment(self):

        self.lock.acquire()#获取锁,进入临界区
        self.value += 1
        value = self.value
        self.lock.release()#释放锁,离开临界区
        return value
        # return self.value

class ThreadCounter(threading.Thread):
    """调用Counter实例,生成线程进行计数"""
    def __init__(self,create_time, counter):
        self.create_time = create_time
        threading.Thread.__init__(self)
        self.counter = counter
    def run(self):
        time.sleep(1.0)
        value = self.counter.increment()
        # print ((time.time() - self.create_time), '\tvalue: ', value)#打印散乱
        print "%f \t value:%d \n" % ((time.time() - self.create_time), value)


if __name__ == "__main__":
    counter = Counter()
    create_time = time.time()
    for i in range(100):
        thread = ThreadCounter(create_time, counter)
        thread.start()

4.线程之间的同步-----条件变量

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@author: ZhongyuanYang
@file: threading_同步test2.py
@time: 2018/9/5 14:23
@desc:测试线程之间的同步-----条件变量
------生产者-消费者问题模型
"""

import threading
import time

class Goods():
    '''产品类'''
    def __init__(self):
        self.count = 0
    def produce(self, num = 1):#生产1个
        self.count += num
    def consume(self):#消耗1个
        self.count -= 1
    def isEmpty(self):#判断产品是否为空
        return not self.count

class Producer(threading.Thread):
    '''生产线程'''
    def __init__(self, condition, goods, sleeptime = 1):
        threading.Thread.__init__(self)
        self.condition = condition
        self.goods = goods
        self.sleeptime = sleeptime

    def run(self):
        while True:
            self.condition.acquire()
            self.goods.produce()
            print "Goods count: %d. Producre thread produced 1 item." % self.goods.count
            self.condition.notifyAll()#唤醒等待此条件的线程
            self.condition.release()
            time.sleep(self.sleeptime)

class Consumer(threading.Thread):
    '''消耗线程'''
    def __init__(self, index, condition, goods, sleeptime=4):
        threading.Thread.__init__(self, name=str(index))
        self.condition = condition
        self.goods = goods
        self.sleeptime = sleeptime

    def run(self):
        while True:
            time.sleep(self.sleeptime)
            self.condition.acquire()
            while self.goods.isEmpty():#如果为空,则等待 被唤醒
                self.condition.wait()#timeout=None

            self.goods.consume()
            print "Goods count: %d. Consumer thread consumed 1 item." % self.goods.count
            self.condition.release()


if __name__ == "__main__":

    goods = Goods()
    condition = threading.Condition()

    producrer = Producer(goods=goods, condition=condition )
    producrer.start()#启动生产线程

    for i in range(5):
        consumer = Consumer(index=i, goods=goods, condition=condition)
        consumer.start()#启动消费线程

5.线程之间的同步-----同步队列 queue

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@author: ZhongyuanYang
@file: threading_同步test3.py
@time: 2018/9/5 15:15
@desc:测试线程之间的同步-----同步队列 queue
"""
'''
此包中的常用方法(q = Queue.Queue()):

q.qsize() 返回队列的大小
q.empty() 如果队列为空,返回True,反之False
q.full() 如果队列满了,返回True,反之False
q.full 与 maxsize 大小对应
q.get([block[, timeout]]) 获取队列,timeout等待时间
q.get_nowait() 相当q.get(False)非阻塞 
q.put(item) 写入队列,timeout等待时间
q.put_nowait(item) 相当q.put(item, False)
q.task_done() 在完成一项工作之后,q.task_done() 函数向任务已经完成的队列发送一个信号
q.join() 实际上意味着等到队列为空,再执行别的操作
'''

import threading, queue
import time, random

class Worker(threading.Thread):
    '''取出队列数据'''
    def __init__(self, index, queue):
        threading.Thread.__init__(self)
        self.index = index
        self.queue = queue

    def run(self):
        while True:
            time.sleep(random.random())
            item = self.queue.get()#同步队列中获取对象
            if item == None:#循环终止条件
                break
            print "task: %d,iterm:%d finished" %(self.index, item)
            self.queue.task_done()#在完成一项工作之后,q.task_done() 函数向任务已经完成的队列发送一个信号。每一条get()语句后需要一条task_done
            # self.queue.join()#等待队列中任务完成操作


if __name__ == "__main__":
    queue = queue.Queue(0)#不限长度

    for i in range(2):
        Worker(index=i, queue=queue).start()#生成两个线程
    for i in range(20):
        queue.put(i)#同步队列中加入对象
    for i in range(2):
        queue.put(None)
    queue.join()  # 等待队列中任务完成操作-----实际上意味着等到队列为空,再执行别的操作





6.信号量 实现同步 等同于 锁机制

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@author: ZhongyuanYang
@file: threading_同步test4.py
@time: 2018/9/5 17:53
@desc:信号量  实现同步   等同于 锁机制
"""
import threading
import time

semaphore = threading.Semaphore(5)

def func():
    if semaphore.acquire():
        print (threading.currentThread().getName() + ' get semaphore')
        time.sleep(2)
        semaphore.release()

for i in range(20):
  t1 = threading.Thread(target=func)
  t1.start()





7.工作者类+调用类+caller的模型

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@author: ZhongyuanYang
@file: 工作者类+调用类+caller的模型.py
@time: 2018/9/4 15:53
@desc:
"""

import os, sys, re, math
import threading
import time
import random


########################################################################
class Soldier(threading.Thread):
    """The class of a soldier."""

    # -------------------------------------------------------------------
    def __init__(self, name):
        """Constructor"""

        threading.Thread.__init__(self, name=name)
        self.name = name  # the name of this soldier
        self.setDaemon(True)  # this is a daemon thread.

        # the time of this soldier need to finish the job
        self.playTime = random.randint(1, 10)##Return random integer in range [a, b], including both end points.

        # is the soldier stop shotting, if timeout or the target has been killed,
        # he may stop.
        self.isStopped = False
        self.isSuccess = False  # did he kill the target?

    # --------------------------------------------------------------------
    def assassinate(self):
        """The task, to kill the target.暗杀任务"""

        for i in range(self.playTime):
            print '%s play(%d)' % (self.name, i + 1)
            time.sleep(1)

        # ----------------------------------------------------------------

    def run(self):
        """Start to move ..."""

        print '%s has moved out, need time: %d ...' % (self.name, self.playTime)
        self.assassinate()
        print '%s stopped ...' % self.name
        self.isStopped = True  # the target has been killed, then he stopped.
        self.isSuccess = True


########################################################################
class Commander(threading.Thread):
    """The class of commander, a commander will command only one soldier."""

    # ----------------------------------------------------------------------
    def __init__(self, soldier):
        """Constructor"""

        threading.Thread.__init__(self, name='Commander')
        self.soldier = soldier

    # ----------------------------------------------------------------------
    def run(self):
        """Authorize the soldier to start killing."""

        self.soldier.start()
        try:
            # Boss said: give the soldier 8 seconds to finish his job
            self.soldier.join(8)
        except:
            pass

            # Use the class's own attribute to judge whether it is timeout.
        # if self.soldier.isAlive():
        if not self.soldier.isStopped:
            print '%s is timeout!' % self.soldier.name

            # the soldier run out his time, then he stopped.
            self.soldier.isStopped = True



# ----------------------------------------------------------------------
def killing():
    """Let's pull the trigger, start killing !"""
    t1 = time.time()

    # Get ready for the commanders
    l_commander = []
    for i in range(10):  # 10 soldiers
        # get ready for the soldier
        soldier = Soldier('soldier-%d' % (i + 1))
        if i == 5 or i == 9:
            soldier.playTime = 10000

        l_commander.append(Commander(soldier))
    # Soldiers move out one by one.
    for cmd in l_commander:
        cmd.start()
    # Judge whether the helicopter should go. If all the soldiers are stop,
    # that is, all finished job or timeout, then it should go!
    isBreak = False
    while not isBreak:
        isBreak = True
    for cmd in l_commander:
        if cmd.soldier.isStopped == False:
            isBreak = False

    # Check the results of the battle at the schedule time.
    for cmd in l_commander:
        print '%s, is success: %s' % (cmd.soldier.name, cmd.soldier.isSuccess)
        # Go back to base.
    time.sleep(20)

    # Check the results at the final time.
    for cmd in l_commander:
        print '%s, is success: %s' % (cmd.soldier.name, cmd.soldier.isSuccess)

    t2 = time.time()
    print 'Total time: %.2f' % (float(t2 - t1))


if __name__ == "__main__":
    killing()

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值