Day9 PythonWeb全栈课程课堂内容

1. 线程方法的补充

import threading
import os
from threading import active_count, current_thread

def task():
	print("hello")
	print(os.getpid())

if __name__ == "__main__":
	t = threading.Thread(target=task)
	t.start()

	print(os.getpid())
  • 主线程和子线程在同一个进程中。

import threading
import os
from threading import active_count, current_thread

def task():
	print("hello")
	

if __name__ == "__main__":
	t = threading.Thread(target=task)
	t.start()

	print(active_count())
  • 返回活跃的线程。返回数字1,
import threading
import os
from threading import active_count, current_thread
import time
def task():
	print("hello")
	time.sleep(1)
	

if __name__ == "__main__":
	t = threading.Thread(target=task)
	t.start()

	print(active_count())
  • 返回活跃的线程。返回数字2。
  • 加了time模块之后,子线程时间变长,活跃数增加。原因子线程已经结束,检测代码只检测到主线程。

import threading
import os
from threading import active_count, current_thread
import time
def task():
	print("hello")
	print(current_thread().name) # Thread-1
	time.sleep(1)
	

if __name__ == "__main__":
	t = threading.Thread(target=task)
	t.start()

	print(current_thread().name) # MainThread
  • 获取线程的名字。

2. 守护线程的补充

import threading
import time

def foo():
	print('123')
	time.sleep(1)
	print('end123')


def foo1():
	print('456')
	time.sleep(1)
	print('end456')

if __name__ == "__main__":
	t1 = threading.Thread(target=foo)
	t2 = threading.Thread(target=foo1)
	t1.daemoin = True
	t1.start()
	t2.start()
	print('MainThread') 

在这里插入图片描述

  • 守护线程有影响,原因是t2子线程并没有结束,而所以守护线程并没有结束,最终end123依旧输出。

3. 多任务版的UDP聊天

import socket
import threading
import time # 防止输入输出同时出现

def send_data(udp_socket):
    while True:
        time.sleep(1)
        send_data = input('Please your input data:')
        udp_socket.sendto(send_data.encode('utf-8'), ('192.168.1.107', 7070))

def recv_data(udp_socket):
    while True:
    	data = udp_socket.recvfrom(1024)
    	print('%s: %s' % (str(data[1]), data[0].decode('utf-8')))


def main():
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_socket.bind(('192.168.1.107', 7070))

    t_send = threading.Thread(target=send_data, args=(udp_socket,))
    t_recv = threading.Thread(target=recv_data, args=(udp_socket,))

    t_send.start()
    t_recv.start()


if __name__ == '__main__':
    main()


4. 多任务TCP

# tcp 客户端
import threading
import socket


client = socket.socket()
client.connect(('127.0.0.1', 7070))

while  True:
	client.send(b'hello world')
	data = client.recv(1024)
	print(data.decode('utf-8'))
# tcp 服务端
import threading
import socket


tcp_server = socket.socket()
tcp_server.bind(('127.0.0.1', 7070))

def main():
    while True:
        tcp_server.listen(128)
        new_client_socket, addr = tcp_server.accept()

        while True:
            recv_data = new_client_socket.recv(1024)
            print(recv_data.decode('utf-8'))
            if recv_data:
                new_client_socket.send('123'.encode('utf-8'))
            else:
                break
        new_client_socket.close()
    tcp_server.close()


if __name__ == '__main__':
    for i in range(3):
        t = threading.Thread(target=main)
        t.start()
  • 可以修改range()内部的数字,来修改线程的数量。

  • 5. 多线程共享全局变量

  • 证明1:

import threading
import time

num = 100
def func():
    global num
    num += 1
    print('func--%d'%num)

def func1():
	print('func1--%d'%num)

def main():
	t1 = threading.Thread(target=func)
	t2 = threading.Thread(target=func1)
	t1.start()
	t2.start()
	print('main--%d'%num)

if __name__ == '__main__':
	main()	

  • 证明2
import threading
import time

num = 100
def func(nums):
    global num
    num += nums
    print('func--%d'%num)

def func1(nums):
    global num
    num += nums
	print('func1--%d'%num)

def main():
	t1 = threading.Thread(target=func,args=(100,))
	t2 = threading.Thread(target=func1,args=(200,))
	t1.start()
	t2.start()
	print('main--%d'%num)

if __name__ == '__main__':
	main()	

在这里插入图片描述

  • 说明了线程是共享全局变量的。

6. 共享全局变量资源竞争

import threading
import time

num = 100
def func(nums):
    global num
    for i in range(nums):
    	num += 1
    print('func--%d'%num)

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

def main():
	t1 = threading.Thread(target=func,args=(100,))
	t2 = threading.Thread(target=func1,args=(200,))
	t1.start()
	t2.start()
	print('main--%d'%num)

if __name__ == '__main__':
	main()	

在这里插入图片描述

  • 当循环次数增大的时候,出现了资源的竞争。

原理:

  • CPU在运行线程时,循环次数越大越有可能发生此概率。

验证此原理:

  • dis模块,先被编译为Python字节码, 再由Python虚拟机来执行字节码。

    import dis
    
    def adds(a):
        a += 1
        
    print(dis.dis(adds)) 
    

在这里插入图片描述

显示内容说明
LOAD_FAST 0(a)进行a参数的操作
LOAD_CONST 1(1)
INPLACE_ADD进行加操作
STORE_FAST 0(a)赋值给a
LOAD_CONST 0(None)
RETURN_VALUE返回值

7. 解决共享全局变量资源竞争的问题

前提

  • 使用互斥锁来解决此问题:

何为互斥锁

  • 当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制
  • 某个线程要更改共享数据时,先将其锁定,此时资源的状态为"锁定",其他线程不能改变,只到该线程释放资源,将资源的状态变成"非锁定",其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。
import threading

# 创建锁,返回一个值。
mutex = threading.Lock() 

# 锁定
mutex.acquire()

# 解锁
mutex.release()
  • 使用在线程当中。
import threading
import time

num = 0
mutex = threading.Lock() 
def func(nums):
    global num
    mutex.acquire()
    for i in range(nums):
    	num += 1
    mutex.release()
    print('func--%d'%num)

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

def main():
    
	t1 = threading.Thread(target=func,args=(10000000,))
	t2 = threading.Thread(target=func1,args=(10000000,))
	t1.start()
	t2.start()
    time.sleep(4)
	print('main--%d'%num)
    

if __name__ == '__main__':
	main()

在这里插入图片描述

  • 当代码中嵌套两把锁,如果继续使用threading.Lock()就会将程序停滞。如果需要嵌套的两把锁就必须得使用threading.RLock()。应用场景,爬取数据时,防止大量数据产生错误。
import threading
import time

num = 0
mutex = threading.RLock() # 可重入的锁
def func(nums):
    global num
    mutex.acquire()
    for i in range(nums):
    	num += 1
    mutex.release()
    print('func--%d'%num)

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

def main():
    
	t1 = threading.Thread(target=func,args=(10000000,))
	t2 = threading.Thread(target=func1,args=(10000000,))
	t1.start()
	t2.start()
    time.sleep(4)
	print('main--%d'%num)
    

if __name__ == '__main__':
	main()

在这里插入图片描述

  • 加锁一定的数量,就必须有相同数量的解锁。

8. 死锁

  • 在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。
import threading
import time

class MyThread1(threading.Thread):
    def run(self):
        # 对mutexA上锁
        mutexA.acquire()

        # mutexA上锁后,延时1秒,等待另外那个线程 把mutexB上锁
        print(self.name+'----do1---up----')
        time.sleep(1)

        # 此时会堵塞,因为这个mutexB已经被另外的线程抢先上锁了
        mutexB.acquire()
        print(self.name+'----do1---down----')
        mutexB.release()

        # 对mutexA解锁
        mutexA.release()

class MyThread2(threading.Thread):
    def run(self):
        # 对mutexB上锁
        mutexB.acquire()

        # mutexB上锁后,延时1秒,等待另外那个线程 把mutexA上锁
        print(self.name+'----do2---up----')
        time.sleep(1)

        # 此时会堵塞,因为这个mutexA已经被另外的线程抢先上锁了
        mutexA.acquire()
        print(self.name+'----do2---down----')
        mutexA.release()

        # 对mutexB解锁
        mutexB.release()

mutexA = threading.Lock()
mutexB = threading.Lock()

if __name__ == '__main__':
    t1 = MyThread1()
    t2 = MyThread2()
    t1.start()
    t2.start()

避免死锁

  • 程序设计时要尽量避免
  • 添加超时时间等

9. 线程同步

import threading


class XiaoAi(threading.Thread):

    def __init__(self, name='小爱'):
        super(XiaoAi, self).__init__(name=name)

    def run(self):
        print("{}:在".format(self.name))
        print("{}:你猜猜现在几点了".format(self.name))


class TianMao(threading.Thread):

    def __init__(self, name='天猫'):
        super(TianMao, self).__init__(name=name)

    def run(self):
        print("{}:小爱同学".format(self.name))
        print("{}:现在几点了?".format(self.name))


if __name__ == "__main__":
    xiaoai = XiaoAi()
    tianmao = TianMao()
    xiaoai.start()
    tianmao.start()

在这里插入图片描述

  • 而修改xiaoai.start()tianmao.start()顺序之后依旧如此。
import threading


class XiaoAi(threading.Thread):

    def __init__(self, name='小爱'):
        super(XiaoAi, self).__init__(name=name)

    def run(self):
        print("{}:在".format(self.name))
        print("{}:你猜猜现在几点了".format(self.name))


class TianMao(threading.Thread):

    def __init__(self, name='天猫'):
        super(TianMao, self).__init__(name=name)

    def run(self):
        print("{}:小爱同学".format(self.name))
        print("{}:现在几点了?".format(self.name))


if __name__ == "__main__":
    xiaoai = XiaoAi()
    tianmao = TianMao()
    tianmao.start()
    xiaoai.start()

在这里插入图片描述

  • 加入锁之后和加入延时之后,你会发现可行。但这只是表面,当代码特别多时,不建议采取此方法。
import threading
import time


class XiaoAi(threading.Thread):

    def __init__(self, lock, name='小爱'):
        super(XiaoAi, self).__init__(name=name)
        self.lock = lock

    def run(self):
        self.lock.acquire()
        print("{}:在".format(self.name))
        self.lock.release()
        time.sleep(1)
        self.lock.acquire()
        print("{}:你猜猜现在几点了".format(self.name))
		self.lock.release()
        

class TianMao(threading.Thread):

    def __init__(self, lock, name='天猫'):
        super(TianMao, self).__init__(name=name)
        self.lock = lock

    def run(self):
        self.lock.acquire()
        print("{}:小爱同学".format(self.name))
        self.lock.release()
        time.sleep(1)
        self.lock.acquire()
        print("{}:现在几点了?".format(self.name))
		self.lock.release()
        

if __name__ == "__main__":
    mutex = threading.Lock()
    xiaoai = XiaoAi(mutex)
    tianmao = TianMao(mutex)
    tianmao.start()
    xiaoai.start()

在这里插入图片描述


  • 现在使用Condition之后。
# @Time : 2021/1/11 23:18
# @Author : Sam
# @File : 线程同步3.py
# @Software: PyCharm
import threading
import time


class XiaoAi(threading.Thread):

    def __init__(self, cond, name='小爱'):
        super(XiaoAi, self).__init__(name=name)
        self.cond = cond

    def run(self):

        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, name='天猫'):
        super(TianMao, self).__init__(name=name)
        self.cond = cond

    def run(self):
        print("{}:小爱同学".format(self.name))
        self.cond.notify()

        self.cond.wait()
        print("{}:现在几点了?".format(self.name))
        self.cond.notify()

if __name__ == "__main__":
    cond = threading.Condition()
    xiaoai = XiaoAi(cond)
    tianmao = TianMao(cond)
    tianmao.start()
    xiaoai.start()

在这里插入图片描述

  • 为什么会产生错误呢?

  • 我们现在从Condition源码中可以得知:我们需要加锁。
    在这里插入图片描述

  • 所以我们在程序中加上锁。

# @Time : 2021/1/11 23:18
# @Author : Sam
# @File : 线程同步3.py
# @Software: PyCharm
import threading
import time


class XiaoAi(threading.Thread):

    def __init__(self, cond, name='小爱'):
        super(XiaoAi, self).__init__(name=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))
            self.cond.notify()

class TianMao(threading.Thread):

    def __init__(self, cond, name='天猫'):
        super(TianMao, self).__init__(name=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()

if __name__ == "__main__":
    cond = threading.Condition()
    xiaoai = XiaoAi(cond)
    tianmao = TianMao(cond)

    xiaoai.start()
    tianmao.start()

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值