"""第一个线程的多任务demo"""
import threading
import time
def sing():
for i in range(5):
print('-----sing----')
time.sleep(1)
def dance():
for i in range(5):
print('----dance----')
time.sleep(1)
def main():
# 创建一个普通的对象,不会创建线程
t1 = threading.Thread(target=sing)
t2 = threading.Thread(target=dance)
# 当调用启动的时候才是线程真正创建的开始
t1.start()
t2.start()
# windows系统中必须要有下面的函数
if __name__ == '__main__':
main()
在threading模块中可以用threading.enumerate()来查看正在运行的线程
"""查看线程的创建和运行过程,查看其那个先创建"""
import threading
import time
def sing():
for i in range(5):
print('----sing----%d \n' % i)
time.sleep(1)
def song():
for i in range(10):
print('----song----%d \n' % i)
time.sleep(1)
def main():
print('main函数执行后执行的线程:' + str(threading.enumerate()) + '\n')
t1 = threading.Thread(target=sing)
print('t1对象创建后执行的线程:' + str(threading.enumerate()) + '\n')
t2 = threading.Thread(target=song)
print('t2对象创建后执行的线程:' + str(threading.enumerate()) + '\n')
t1.start()
print('t1对象start后的线程数:\n' + str(threading.enumerate())+ '\n')
t2.start()
print('t2对象start后的线程数:\n' + str(threading.enumerate()) + '\n')
if __name__ == '__main__':
main()
全局变量和局部变量:一个在函数里面一个在函数外面
在函数里面修改全局变量的做法:使用global和不使用global(值获取的不用加global)
只要指向的是可变的都可以不使用global,不可变的数据:数字、元组、字符串;其他都可变
举例:
"""多线程共享全局变量"""
import threading
import time
g_num = 100 # 这个要使用global
list = [1,2] # 这个在函数中执行的时候要是不改变他的指向就不需要使用global
def test1():
"""改变全局变量"""
global g_num
g_num += 1
list.append(1)
print('-----test1----g_num:%d----' % g_num)
print(f'list初始:[1,2]检查是否可以在不使用global的情况下使用全局变量:{list}')
def test2():
"""打印全局变量g_num,如果共享则打印的全局变量为101"""
global g_num
print('----test2----g_num:%d----' % g_num)
print(f'----test2----list:{list}----')
def main():
t1 = threading.Thread(target=test1)
t2 = threading.Thread(target=test2)
t1.start()
time.sleep(1) # 确保test1先执行
t2.start()
time.sleep(1)
print('----in main g_num = %d----' % g_num)
if __name__ == '__main__':
main()
但是共享全局变量也会出现一些问题:如:资源竞争的问题:请看一下实例:
"""多线程出现的问题:资源竞争 计算10000000+10000000"""
import threading
import time
g_num = 0
def test1(temp):
global g_num
for i in range(temp):
g_num += 1
print('----in test1 g_num = %d----' % g_num)
def test2(temp):
global g_num
for i in range(temp):
g_num += 1
print('----in test2 g_num = %d----' % g_num)
def main():
# 当args传的数值增大,即每个线程循环加的次数增多的时候,会出现资源竞争的问题会出现相加的值与实际值不符
t1 = threading.Thread(target=test1, args=(10000000, ))
t2 = threading.Thread(target=test2, args=(10000000, ))
t1.start()
t2.start()
time.sleep(5)
print('----in main g_num=%d----' % g_num)
if __name__ == '__main__':
main()
运行结果:
由此图可见:多线程中如果发生资源的竞争会导致计算的结果和实际的结果不符
当多线程几乎同时修改某一个共享数据的时候,需要进行同步控制,则可以使用互斥锁
互斥锁为资源引入状态:锁定/非锁定
当某个线程要修改共享资源的时候,现将资源状态改为锁定,其他线程不能修改,直到该线程释放资源,将资源状态改为非锁定。这样就会保证了多线程下共享数据的正确性。
互斥锁的使用方法:
互斥锁:
创建互斥锁: mutex = treading.Lock()
锁定: mutex.acquire()
解锁: mutex.release()
获取锁是否上锁: mutex.locked()
用互斥锁:( 计算10000000+10000000):
5.1 方法一:(体现不出多任务)
执行结果:
"""多线程出现的问题:资源竞争 解决方法一"""
import threading
import time
g_num = 0
# 创建互斥锁, 默认是没有上锁的
mutex = threading.Lock()
def test1(temp):
global g_num
# 上锁,如果之前没有被上锁,那么此时上锁成功
# 如果之前已经被上锁了,那么此时会堵塞在这里,直到这个锁被解开位置
# 只有这个循环做完了才会给解锁,让下一个加锁的线程运行
mutex.acquire()
for i in range(temp):
g_num += 1
# 解锁
mutex.release()
print('----in test1 g_num = %d----' % g_num)
def test2(temp):
global g_num
mutex.acquire()
for i in range(temp):
g_num += 1
mutex.release()
print('----in test2 g_num = %d----' % g_num)
def main():
# 当args传的数值增大,即每个线程循环加的次数增多的时候,会出现资源竞争的问题会出现相加的值与实际值不符
t1 = threading.Thread(target=test1, args=(10000000, ))
t2 = threading.Thread(target=test2, args=(10000000, ))
t1.start()
t2.start()
time.sleep(5)
print('----in main g_num=%d----' % g_num)
if __name__ == '__main__':
main()
"""多线程出现的问题:资源竞争 解决方法二"""
import threading
import time
g_num = 0
# 创建互斥锁, 默认是没有上锁的
mutex = threading.Lock()
def test1(temp):
global g_num
# 上锁,如果之前没有被上锁,那么此时上锁成功
# 如果之前已经被上锁了,那么此时会堵塞在这里,直到这个锁被解开位置
for i in range(temp):
# 只给相加的位置上锁,加完然后就解锁
mutex.acquire()
g_num += 1
# 解锁
mutex.release()
print('----in test1 g_num = %d----' % g_num)
def test2(temp):
global g_num
for i in range(temp):
mutex.acquire()
g_num += 1
mutex.release()
print('----in test2 g_num = %d----' % g_num)
def main():
# 当args传的数值增大,即每个线程循环加的次数增多的时候,会出现资源竞争的问题会出现相加的值与实际值不符
t1 = threading.Thread(target=test1, args=(10000000, ))
t2 = threading.Thread(target=test2, args=(10000000, ))
t1.start()
t2.start()
time.sleep(5)
print('----in main g_num=%d----' % g_num)
if __name__ == '__main__':
main()
""""多线程解决资源竞争问题时创建互斥锁出现的问题-->死锁"""
import threading
import time
# 创建两个互斥锁
mutexA = threading.Lock()
mutexB = threading.Lock()
class Mythread1(threading.Thread):
def run(self):
# 对mutexA上锁
mutexA.acquire()
# mutexA上锁后,延迟1s,等待另外一个线程把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上锁后,延迟1s,等待另外一个线程把mutexA上锁
print(self.name + '----do2----up----')
time.sleep(1)
# 此时会出现堵塞,因为这个mutexA已经被另外一个线程抢先锁上
mutexA.acquire()
print(self.name + '----do1----down----')
mutexA.release()
# 对mutexB解锁
mutexB.release()
def main():
t1 = Mythread1()
t2 = Mythread2()
t1.start()
t2.start()
if __name__ == "__main__":
main()
运行结果:导致程序卡死"""udp多线程聊天器"""
import socket
import threading
def recv_msg(udp_socket_t):
"""接受数据"""
# 接受数据
while True:
recv_data = udp_socket_t.recvfrom(1024)
print(recv_data)
def send_msg(udp_socket_t, socket_ip, socket_prot):
"""发送数据"""
# 发送数据
while True:
send_data = input('请输入要发送的数据:')
udp_socket_t.sendto(send_data.encode('gbk'), (socket_ip, socket_prot))
def main():
# 1.创建套接字
udp_socket_t = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 2.绑定ip和prot
udp_socket_t.bind(("",7890))
# 3.获取对方的ip和prot
socket_ip = input('请输入对方的ip:')
socket_prot = int(input('请输入对方的prot:'))
# 4.使用多线程收发消息
# 发送的线程
send_t = threading.Thread(target=send_msg, args=(udp_socket_t, socket_ip, socket_prot, ))
# 接受数据的线程
recv_t = threading.Thread(target=recv_msg , args=(udp_socket_t, ))
# 启动线程
send_t.start()
recv_t.start()
# 5.关闭套接字
# udp_socket_t.close()
if __name__ == '__main__':
main()