Python高级编程技巧--线程

线程的概念

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

多任务

就是电脑同时执行多个任务,但是其实是轮转,并不是真的一起运行,叫时间片轮转
并发: CPU小于执行的任务
并行: CPU大于执行的任务

线程

主线程:
代码从上往下执行,主线程会默认等到子线程执行完毕然后在关闭

import threading
import time


def sing():
    for i in range(5):
        print('正在唱歌。。。')
        time.sleep(1)


def dance():
    for i in range(5):
        print('正在跳舞。。。')
        time.sleep(1)


def main():
    t1 = threading.Thread(target=sing)  
    t2 = threading.Thread(target=dance)
    t1.start()   # 这里创建子线程并且运行子线程
    t2.start()


if __name__ == '__main__':
    main()

注:子线程里面还可以创建子线程
守护主线程:就是不等待子线程执行完成直接走

setDaemon(True)

等到子线程执行完, 默认是主线程先走,最后会等待子线程执行结束才会停止

jion()

查看线程的数量

print(threading.enumerate())

线程执行没有顺序
线程真正创建并运行是在start那里

通过类来创建线程

import threading


class A(threading.Thread):
    def run(self):   # 只能通过run方法添加子线程
        for i in range(5):
            print(i)

if __name__ == '__main__':
    a = A()
    a.start()
线程间的通信

修改全局变量一定是要加上global吗?
int是不可变对象,所以不管怎么样都需要加上global
如 :

num = 100


def demo():
    global num
    num += 100
    print(num)
print(num)  # 100
demo()      # 200
print(num)  # 200

但是列表就不一样,列表是可变的,对于可变的对象,只要没有改变其指向就不需要添加global
如:

lis = [11, 22]


def demo():
	lis.append(33)   # 其指向并没有改变,所以可以进行添加
	lis = lis + [44]   # 赋值的指向已经改变了,不能进行添加


demo()
多线程共享全局变量
import threading
import time

num = 100


def demo1():
    global num
    num += 1
    print('demo1-->%d' % num)


def demo2():
    print('demo2-->%d' % num)


if __name__ == '__main__':
    t1 = threading.Thread(target=demo1)
    t2 = threading.Thread(target=demo2)
    t1.start()
    time.sleep(1)
    t2.start()
    time.sleep(1)
    print('main-->%d' % num)
"""
demo1-->101
demo2-->101
main-->101
"""

传参

args=(), 必须传一个元组
全局变量的资源竞争

因为线程的执行顺序是没有的,所以谁先抢到资源谁就先执行
如:

import threading

num = 0


def demo1(nums):

    for i in range(nums):
        global num
        num += 1  # 1.获取num的值 2.获取n+=1 3.保存num的值  之所以值不一样是因为两个函数里面的这3步不一定都是执行完
    print("demo1---%d" % num)


def demo2(nums):
    for i in range(nums):
        global num
        num += 1
    print("demo2---%d" % num)


def main():
    t1 = threading.Thread(target=demo1, args=(100000,))
    t2 = threading.Thread(target=demo2, args=(100000,))
    t1.start()
    t2.start()
    print("main()---%d" % num)


if __name__ == '__main__':
    main()

“”“
demo1---141635
demo2---184111
main()---184111
”“”

得到的结果不一定正确,这是因为上面分解的步骤不一定是按照想的那样执行,所以值是不正确的,但是我们可以通过加上锁来完成。
如何在线程上添加锁呢?

import threading
import time

mutex = threading.Lock()
num = 0


def demo1(nums):
    # 添加互斥锁
    mutex.acquire()
    for i in range(nums):
        global num
        num += 1  # 1.获取num的值 2.获取n+=1 3.保存num的值  之所以值不一样是因为两个函数里面的这3步不一定都是执行完
    mutex.release()
    print("demo1---%d" % num)


def demo2(nums):
    mutex.acquire()
    for i in range(nums):
        global num
        num += 1
    mutex.release()
    print("demo2---%d" % num)


def main():
    t1 = threading.Thread(target=demo1, args=(100000,))
    t2 = threading.Thread(target=demo2, args=(100000,))
    t1.start()
    t2.start()
    time.sleep(1)
    print("main()---%d" % num)


if __name__ == '__main__':
    main()
"""
demo1---100000
demo2---200000
main()---200000
"""

还可以用可重入锁RLock()可以同时加上多个锁,但是必须解那么多个锁

线程同步

用线程完成
天猫精灵:小爱同学
小爱同学:在
天猫精灵:现在几点了?
小爱同学:你猜猜现在几点了
Condition

  1. 可添加等待,然后再唤醒从而完成
  2. wait() 是等待,必须要有 notify() 把他唤醒
import threading


class XiaoAi(threading.Thread):
    def __init__(self, cond):
        super().__init__(name='小爱同学')
        self.cond = cond

    def run(self):
        with self.cond:
            self.cond.wait()
            print('{}:在'.format(self.name))
            self.cond.notify()
            self.cond.wait()
            print('{}:你猜猜现在几点了'.format(self.name))


class TianMao(threading.Thread):
    def __init__(self, cond):
        super().__init__(name='天猫精灵')
        self.cond = cond

    def run(self):
        with self.cond:
            print('{}:小爱同学'.format(self.name))
            self.cond.notify()
            self.cond.wait()
            print('{}:现在几点了?'.format(self.name))
            self.cond.notify()


def main():
    cond = threading.Condition()
    t1 = TianMao(cond)
    t2 = XiaoAi(cond)
    t2.start()
    t1.start()
udp聊天器

利用解耦的思想,发送和接受数据单独写一个函数,然后在利用线程来完成多任务

import threading
import socket


def send_data(udp_socket):
    while True:
        data = input('需要发送的数据:')
        udp_socket.sendto(data.encode('gbk'), ('192.168.0.119', 8080))


def recv_data(udp_socket):
    udp_socket.bind(('', 7892))
    while True:
        recv_data = udp_socket.recvfrom(1024)   # 返回的是一个元组,(内容,对方ip端口)
        print(recv_data[0].decode('gbk'))
def main():
    # 创建套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 创建子线程同时进行
    t_recv = threading.Thread(target=recv_data, args=(udp_socket,))
    t_send = threading.Thread(target=send_data, args=(udp_socket,))
    t_recv.start()
    t_send.start()


if __name__ == '__main__':
    main()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值