多线程

作者: wangyu2488 | 来源:发表于2019-12-22 14:27 被阅读0次

2019年12月19日

一.概念

1.进程

image.png

2.线程

image.png

3.多线程开发 推荐用threading

image.png
import threading

# 当前线程对象
t = threading.current_thread()
# 当前线程名
print(t.name)

# 返回当前处于活动状态的线程个数
print(threading.active_count())
# 当主线程对象
t = threading.main_thread()
# 主线程名
print(t.name)
image.png

二.创建线程

image.png

1.方法1创建线程

# coding=utf-8

import threading
import time

# 线程体函数
def thread_body():
    # 当前线程对象
    t = threading.current_thread()
    for n in range(2):
        # 当前线程名
        print('第{0}次执行线程{1}'.format(n, [t.name](http://t.name/)))
        # 线程休眠
        time.sleep(1)
    print('线程{0}执行完成!'.format(t.name))

# 主函数
def main():
    # 创建线程对象t1
    t1 = threading.Thread(target=thread_body)
    # 启动线程t1
    t1.start()

    # 创建线程对象t2
    t2 = threading.Thread(target=thread_body, name='MyThread')
    # 启动线程t2
    t2.start()

if __name__ == '__main__':
    main()

休眠可以看出是交替执行

image.png

2.方法2创建线程 (继承线程类)

# coding=utf-8

import threading
import time

class MyThread(threading.Thread):
    def __init__(self, name=None):
        super().__init__(name=name)

    # 线程体函数
    def run(self):
        # 当前线程对象
        t = threading.current_thread()
        for n in range(2):
            # 当前线程名
            print('第{0}次执行线程{1}'.format(n, t.name))

            # 线程休眠
            time.sleep(1)
        print('线程{0}执行完成!'.format(t.name))

# 主函数
def main():
    # 创建线程对象t1
    t1 = MyThread()
    # 启动线程t1
    t1.start()

    # 创建线程对象t2
    t2 = MyThread(name='MyThread')
    # 启动线程t2
    t2.start()

if __name__ == '__main__':
    main()

三.线程的管理 (等待线程结束和线程停止)

image.png

1.等待线程结束例子(join)

# coding=utf-8

import threading
import time

# 共享变量
value = 0

# 线程体函数
def thread_body():
    global value
    # 当前线程对象
    print('ThreadA 开始...')
    for n in range(2):
        print('ThreadA 执行...')
        value += 1
        # 线程休眠
        time.sleep(1)
    print('ThreadA 结束...')

# 主函数
def main():
    print('主线程 开始...')
    # 创建线程对象t1
    t1 = threading.Thread(target=thread_body, name='ThreadA')
    # 启动线程t1
    t1.start()
    # 主线程被阻塞,等待t1线程结束
    t1.join()
    print('value = {0}'.format(value))
    print('主线程 结束...')

if __name__ == '__main__':
    main()
image.png

2.线程停止 (while循环的需要添置,通过全局变量来控制)

# coding=utf-8

import threading
import time

# 线程停止变量
isrunning = True

# 线程体函数
def thread_body():
    while isrunning:
        # 线程开始工作
        # TODO
        print('下载中...')
        # 线程休眠
        time.sleep(5)
    print('执行完成!')

# 主函数
def main():
    # 创建线程对象t1
    t1 = threading.Thread(target=thread_body)
    # 启动线程t1
    t1.start()
    # 从键盘输入停止指令 exit
    command = input('请输入停止指令:')
    if command == 'exit':
        global isrunning
        isrunning = False

if __name__ == '__main__':
    main()
image.png

四.线程安全

1.临界资源问题

image.png

销售机票例子(错误的例子)

# coding=utf-8

import threading
import time

class TicketDB:
    def __init__(self):
        # 机票的数量
        self.ticket_count = 5

    # 获得当前机票数量
    def get_ticket_count(self):
        return self.ticket_count

    # 销售机票
    def sell_ticket(self):
        # TODO 等于用户付款
        # 线程休眠,阻塞当前线程,模拟等待用户付款
        time.sleep(1)
        print("第{0}号票,已经售出".format(self.ticket_count))
        self.ticket_count -= 1

# 创建TicketDB对象
db = TicketDB()

# 线程体1函数
def thread1_body():
    global db  # 声明为全局变量
    while True:
        curr_ticket_count = db.get_ticket_count()
        # 查询是否有票
        if curr_ticket_count > 0:
            db.sell_ticket()
        else:
            # 无票退出
            break

# 线程体2函数
def thread2_body():
    global db  # 声明为全局变量
    while True:
        curr_ticket_count = db.get_ticket_count()
        # 查询是否有票
        if curr_ticket_count > 0:
            db.sell_ticket()
        else:
            # 无票退出
            break

# 主函数
def main():
    # 创建线程对象t1
    t1 = threading.Thread(target=thread1_body)
    # 启动线程t1
    t1.start()
    # 创建线程对象t2
    t2 = threading.Thread(target=thread2_body)
    # 启动线程t2
    t2.start()

if __name__ == '__main__':
    main()

有问题 两个5了

image.png

2.多线程同步[解决上面数据出错的问题]

image.png
# coding=utf-8

import threading
import time

class TicketDB:
    def __init__(self):
        # 机票的数量
        self.ticket_count = 5

    # 获得当前机票数量
    def get_ticket_count(self):
        return self.ticket_count

    # 销售机票
    def sell_ticket(self):
        # TODO 等于用户付款
        # 线程休眠,阻塞当前线程,模拟等待用户付款
        time.sleep(1)
        print(threading.current_thread().name)
        print("第{0}号票,已经售出".format(self.ticket_count))
        self.ticket_count -= 1

# 创建TicketDB对象
db = TicketDB()
# 创建Lock对象
lock = threading.Lock()

# 线程体1函数
def thread1_body():
    global db, lock  # 声明为全局变量
    while True:
        lock.acquire()
        curr_ticket_count = db.get_ticket_count()
        # 查询是否有票
        if curr_ticket_count > 0:
            db.sell_ticket()
        else:
            lock.release()
            # 无票退出
            break
        lock.release()
        time.sleep(1)

# 线程体2函数
def thread2_body():
    global db, lock  # 声明为全局变量
    while True:
        lock.acquire()
        curr_ticket_count = db.get_ticket_count()
        # 查询是否有票
        if curr_ticket_count > 0:
            db.sell_ticket()
        else:
            lock.release()
            # 无票退出
            break
        lock.release()
        time.sleep(1)

# 主函数
def main():
    # 创建线程对象t1
    t1 = threading.Thread(target=thread1_body)
    # 启动线程t1
    t1.start()
    # 创建线程对象t2
    t2 = threading.Thread(target=thread2_body)
    # 启动线程t2
    t2.start()

if __name__ == '__main__':
    main()
image.png

五.线程之间通信

通信可以使用threading模块的Condition 和 Event类

1.Condition

image.png
# coding=utf-8

import threading
import time

# 创建条件变量对象
condition = threading.Condition()

class Stack:
    def __init__(self):
        # 堆栈指针初始值为0
        self.pointer = 0
        # 堆栈有5个数字的空间
        self.data = [-1, -1, -1, -1, -1]

    # 压栈方法
    def push(self, c):
        global condition
        condition.acquire()
        # 堆栈已满,不能压栈
        while self.pointer == len(self.data):
            # 等待其它线程把数据出栈
            condition.wait()
        # 通知其他线程把数据出栈
        condition.notify()
        # 数据压栈
        self.data[self.pointer] = c
        # 指针向上移动
        self.pointer += 1
        condition.release()

    # 出栈方法
    def pop(self):
        global condition
        condition.acquire()
        # 堆栈无数据,不能出栈
        while self.pointer == 0:
            # 等待其他线程把数据压栈
            condition.wait()
        # 通知其他线程压栈
        condition.notify()
        # 指针向下移动
        self.pointer -= 1
        data = self.data[self.pointer]
        condition.release()
        # 数据出栈
        return data

# 创建堆栈Stack对象
stack = Stack()

# 生产者线程体函数
def producer_thread_body():
    global stack  # 声明为全局变量
    # 产生10个数字
    for i in range(0, 10):
        # 把数字压栈
        stack.push(i)
        # 打印数字
        print('生产:{0}'.format(i))
        # 每产生一个数字线程就睡眠
        time.sleep(1)

# 消费者线程体函数
def consumer_thread_body():
    global stack  # 声明为全局变量
    # 从堆栈中读取数字
    for i in range(0, 10):
        # 从堆栈中读取数字
        x = stack.pop()
        # 打印数字
        print('消费:{0}'.format(x))
        # 每消费一个数字线程就睡眠
        time.sleep(1)

# 主函数
def main():
    # 创建生产者线程对象producer
    producer = threading.Thread(target=producer_thread_body)
    # 启动生产者线程
    producer.start()
    # 创建消费者线程对象consumer
    consumer = threading.Thread(target=consumer_thread_body)
    # 启动消费者线程
    consumer.start()

if __name__ == '__main__':
    main()

正常现象

image.png

2.Event

image.png
# coding=utf-8

import threading
import time

event = threading.Event()

class Stack:
    def __init__(self):
        # 堆栈指针初始值为0
        self.pointer = 0
        # 堆栈有5个数字的空间
        self.data = [-1, -1, -1, -1, -1]

    # 压栈方法
    def push(self, c):
        global event
        # 堆栈已满,不能压栈
        while self.pointer == len(self.data):
            # 等待其它线程把数据出栈
            event.wait()
        # 通知其他线程把数据出栈
        event.set()
        # 数据压栈
        self.data[self.pointer] = c
        # 指针向上移动
        self.pointer += 1

    # 出栈方法®
    def pop(self):
        global event
        # 堆栈无数据,不能出栈
        while self.pointer == 0:
            # 等待其他线程把数据压栈
            event.wait()
        # 通知其他线程压栈
        event.set()
        # 指针向下移动
        self.pointer -= 1
        # 数据出栈
        data = self.data[self.pointer]
        return data

# 创建堆栈Stack对象
stack = Stack()

# 生产者线程体函数
def producer_thread_body():
    global stack  # 声明为全局变量
    # 产生10个数字
    for i in range(0, 10):
        # 把数字压栈
        stack.push(i)
        # 打印数字
        print('生产:{0}'.format(i))
        # 每产生一个数字线程就睡眠
        time.sleep(1)

# 消费者线程体函数
def consumer_thread_body():
    global stack  # 声明为全局变量
    # 从堆栈中读取数字
    for i in range(0, 10):
        # 从堆栈中读取数字
        x = stack.pop()
        # 打印数字
        print('消费:{0}'.format(x))
        # 每消费一个数字线程就睡眠
        time.sleep(1)

# 主函数
def main():
    # 创建生产者线程对象producer
    producer = threading.Thread(target=producer_thread_body)
    # 启动生产者线程
    producer.start()
    # 创建消费者线程对象consumer
    consumer = threading.Thread(target=consumer_thread_body)
    # 启动消费者线程
    consumer.start()

if __name__ == '__main__':
    main()

正常现象

image.png

如果您发现本文对你有所帮助,如果您认为其他人也可能受益,请把它分享出去。

相关文章

  • iOS多线程 NSOperation

    系列文章: 多线程 多线程 pthread、NSThread 多线程 GCD 多线程 NSOperation 多线...

  • iOS多线程 pthread、NSThread

    系列文章: 多线程 多线程 pthread、NSThread 多线程 GCD 多线程 NSOperation 多线...

  • iOS多线程: GCD

    系列文章: 多线程 多线程 pthread、NSThread 多线程 GCD 多线程 NSOperation 多线...

  • iOS多线程运用

    系列文章: 多线程 多线程 pthread、NSThread 多线程 GCD 多线程 NSOperation 多线...

  • iOS多线程基础

    系列文章: 多线程 多线程 pthread、NSThread 多线程 GCD 多线程 NSOperation 多线...

  • 多线程介绍

    一、进程与线程 进程介绍 线程介绍 线程的串行 二、多线程 多线程介绍 多线程原理 多线程的优缺点 多线程优点: ...

  • iOS进阶之多线程管理(GCD、RunLoop、pthread、

    深入理解RunLoopiOS多线程--彻底学会多线程之『GCD』iOS多线程--彻底学会多线程之『pthread、...

  • iOS多线程相关面试题

    iOS多线程demo iOS多线程之--NSThread iOS多线程之--GCD详解 iOS多线程之--NSOp...

  • 多线程之--NSOperation

    iOS多线程demo iOS多线程之--NSThread iOS多线程之--GCD详解 iOS多线程之--NSOp...

  • iOS多线程之--NSThread

    iOS多线程demo iOS多线程之--NSThread iOS多线程之--GCD详解 iOS多线程之--NSOp...

网友评论

      本文标题:多线程

      本文链接:https://www.haomeiwen.com/subject/mvsonctx.html