Python多线程通信_python socket多线程

Python多线程通信_python socket多线程作者:billy版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处创建线程线程(Thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一个线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每个线程并行执行不同的任务。由于线程是操作系统直接支持的执行单元,因此,高级语言(如Python、Java等)通常都内置多线程的支持。Python的标准库提供了两个模块:_thread和threading,_thread

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

作者:billy
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

创建线程

线程(Thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一个线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每个线程并行执行不同的任务。

由于线程是操作系统直接支持的执行单元,因此,高级语言(如 Python、Java 等)通常都内置多线程的支持。Python 的标准库提供了两个模块:_thread 和 threading,_thread 是低级模块,threading 是高级模块,对 _thread 进行了封装。绝大多数情况下,我们只需要使用 threading 这个模块。

  1. 使用 threading 模块创建线程
    threading 模块提供了一个 Thread 类来代表一个线程对象,其语法如下:
    Thread(group [, target [, name [, args [, kwaegs]]]])
    group:参数未使用,值始终为 None;
    target:表示一个可调用对象,线程启动时,run() 方法将调用此对象,默认值为 None,表示不调用任何内容;
    name:为当前线程名称,默认创建一个 Thread-N 格式的唯一名称;
    args:表示传递给 target 函数的参数元组;
    kwargs:表示传递给 target 函数的参数字典;

对比发现,Thread 类和上一章节中的 Process 类的方法基本相同,直接上案例:

import threading, time

def process():
    for i in range(3):
        time.sleep(1)
        print("thread name is %s" % threading.current_thread().name)

if __name__ == '__main__':
    print("---主线程开始---")
    threads = [threading.Thread(target=process) for i in range(4)]  # 创建 4 个线程,存入列表
    for th in threads:
        th.start()
    for th in threads:
        th.join()
    print("---主线程结束---")

上述例子的运行结果为:

---主线程开始---
thread name is Thread-3
thread name is Thread-2
thread name is Thread-1
thread name is Thread-4
thread name is Thread-4
thread name is Thread-1
thread name is Thread-3
thread name is Thread-2
thread name is Thread-1
thread name is Thread-4
thread name is Thread-2
thread name is Thread-3
---主线程结束---
  1. 使用 Thread 子类创建线程
    Thread 线程类和 Process 进程类使用方式非常相似,也可以通过定义一个子类,使其继承 Thread 线程类来创建线程。

示例:

import threading, time

class SubThread(threading.Thread):
    def run(self):
        for i in range(3):
            time.sleep(1)
            msg = "子线程" + self.name + "执行,i = " + str(i)    # name 为属性中保存的当前线程的名字
            print(msg)

if __name__ == '__main__':
    print("---主线程开始---")
    t1 = SubThread()
    t2 = SubThread()
    t1.start()  # start() 方法开启线程,会自动调用 run() 方法
    t2.start()
    t1.join()
    t2.join()
    print("---主线程结束---")

上述例子的运行结果为:

---主线程开始---
子线程Thread-2执行,i = 0
子线程Thread-1执行,i = 0
子线程Thread-2执行,i = 1
子线程Thread-1执行,i = 1
子线程Thread-1执行,i = 2
子线程Thread-2执行,i = 2
---主线程结束---

互斥锁

在一个进程内的所有线程是共享全局变量的,由于线程可以对全局变量随意修改,这就可能造成多线程之间全局变量的混乱。这就需要用到互斥锁(Mutual exclusion,缩写 Mutex),防止多个线程同时读写某一块内存区域

互斥锁为资源引入一个状态:锁定和非锁定。某个线程要更改共享数据时,先将其锁定,此时资源的状态为 “锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成 “非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性

在 threading 模块中使用 Lock 类可以方便处理锁定。Lock 类有两个方法:acquire() 锁定和 release() 释放锁。语法如下:

mutex = threading.Lock()		# 创建锁
mutex.acquire([blocking])		# 锁定
mutex.release()				# 释放锁

示例:

from threading import Thread, Lock
import time

n = 100 # 共 100 张电影票

def task():
    global n
    mutex.acquire()     # 上锁
    temp = n            # 赋值给临时变量
    time.sleep(0.5)     # 睡眠 0.5 秒
    n = temp - 1        # 数量减 1
    print("购买成功,剩余 %d 张电影票" % n)
    mutex.release()     # 释放锁

if __name__ == '__main__':
    mutex = Lock() 
    list = []
    for i in range(10):
        th = Thread(target=task)
        list.append(th)
        th.start()
    for th in list:
        th.join()

上述例子的运行结果为:

购买成功,剩余 99 张电影票
购买成功,剩余 98 张电影票
购买成功,剩余 97 张电影票
购买成功,剩余 96 张电影票
购买成功,剩余 95 张电影票
购买成功,剩余 94 张电影票
购买成功,剩余 93 张电影票
购买成功,剩余 92 张电影票
购买成功,剩余 91 张电影票
购买成功,剩余 90 张电影票

使用队列在线程间通信

我们知道 mutliprocessing 模块的 Queue 队列可以实现进程间通信,同样在线程间也可以使用 Queue 队列实现线程间通信。不同之处在于我们需要使用 queue 模块的 Queue 队列,而不是 multiprocessing 模块的 Queue 队列。但使用方法相同

示例:

from queue import Queue
import random, threading, time

# 生产者类
class Producer(threading.Thread):
    def __init__(self, name, queue):
        threading.Thread.__init__(self, name=name)
        self.data = queue
    def run(self):
        for i in range(5):
            print("生产者 %s 将产品 %d 加入队列" % (self.getName(), i))
            self.data.put(i)
            time.sleep(random.random())
        print("生产者 %s 完成" % self.getName())

# 消费者类
class Consumer(threading.Thread):
    def __init__(self, name, queue):
        threading.Thread.__init__(self, name=name)
        self.data = queue
    def run(self):
        for i in range(5):
            val = self.data.get()
            print("消费者 %s 将产品 %d 从队列中取出" % (self.getName(), val))
            time.sleep(random.random())
        print("消费者 %s 完成" % self.getName())

if __name__ == '__main__':
    print("---主线程开始---")
    queue = Queue()                         # 实例化队列
    producer = Producer("Producer", queue)  # 实例化线程 Producer,并传入队列作为参数
    consumer = Consumer("Consumer", queue)  # 实例化线程 Consumer,并传入队列作为参数
    producer.start()                        # 启动线程 Producer
    consumer.start()                        # 启动线程 Consumer
    producer.join()                         # 等待线程 Producer 结束
    consumer.join()                         # 等待线程 Consumer 结束
    print("---主线程结束---")

上述例子的运行结果为:

---主线程开始---
生产者 Producer 将产品 0 加入队列
消费者 Consumer 将产品 0 从队列中取出
生产者 Producer 将产品 1 加入队列
消费者 Consumer 将产品 1 从队列中取出
生产者 Producer 将产品 2 加入队列
消费者 Consumer 将产品 2 从队列中取出
生产者 Producer 将产品 3 加入队列
生产者 Producer 将产品 4 加入队列
消费者 Consumer 将产品 3 从队列中取出
消费者 Consumer 将产品 4 从队列中取出
生产者 Producer 完成
消费者 Consumer 完成
---主线程结束---

更多请参考

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/185303.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 青龙面板一键搭建(openwrt安装青龙面板)

    大家好,QX系列教程教会了大家js脚本挂机的基础玩法,Boxjs为这个玩法提升了不少可玩性,但是IOS系统下最多支持2个账号,许多助力需求无法满足,应群友要求出一个青龙从零开始搭建教程,欢迎大家入群交流:106511927注意教程看不懂的话可以进群找群主帮你代挂!如果本教程看不懂或者操作出现问题,证明您的计算机专业知识并不支持本文章的搭建操作。第一步购买云服务器个人推荐阿里云服务器1核2G即可搞活动一年一百来块钱系统选择CentOs7等待配置完成。百度搜索Finalshell下载安装

    2022年4月18日
    227
  • JSQI网站大事表 | Website Landmark

    JSQI网站大事表 | Website Landmark

    2021年11月17日
    55
  • Oracle去重查询实例

    Oracle去重查询实例Oracle去重查询实例今天工作中遇到了一个关于去重的查询,琢磨了半天,终于想明白了,这里简单记录一下。distinct函数说到去重,可能第一反应就是distinct函数,但其实distinct只是针对单一字段的去重有效。例如我想查库中所有的不重复的空号手机数量,如下即可selectcount(distinctn.phonenumber)fromIVR_NO_EXISTn这样查出来一共有295136个空号之后我想查出每天识别出的不重复的空号有多少,开始没想太多,直接写了sel

    2025年6月10日
    5
  • JAVA异或运算符_java位运算符详解

    JAVA异或运算符_java位运算符详解目录目录性质应用举例其他用途示例异或是一种基于二进制的位运算,用符号XOR或者^表示,起运算法则是对运算符两侧数的每一个二进制位同值则取0,异值则取1.简单理解就是不进位加法,如1+1=0,0+0=0,1+0=1.性质1、交换律2、结合律(即(a^b)^c==a^(b^c))3、对于任何数x,都有x^x=0,x^0=x4、自反性AXORBXORB=

    2022年10月4日
    2
  • 5G 信道一览表

    5G 信道一览表各个地区2.4G及5G信道一览表美洲(FCC)2.412~2.462GHz:11个信道5.15~5.35GHz,5.725~5.825GHz;12个信道中国2.412~2.472GHz:13个信道5.725~5.825GHz:4个信道ETSI2.412~2.472GHz:13个信道5.15~5.35GHz:8个信道5470…

    2022年6月7日
    267
  • android100 自定义内容提供者

    android100 自定义内容提供者#ContentProvider,就是来操作数据的,增删改查,*四大组件之一*应用的数据库是不允许其他应用访问的*内容提供者的作用就是让别的应用访问到你的数据库*内容提供者的作用:把私有数据暴

    2022年7月1日
    20

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号