Python学习(二)线程

线程

多线程
利用多线程实现TCP客户端:

import socket
#导入模块
import threading



def tcp_send():
    tcp_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    address = (('192.168.110.128',8080))
    tcp_socket.connect(address)
    while True:
        send_data = input('发送:')
        tcp_socket.send(send_data.encode('utf-8'))
    tcp_socket.close()


def tcp_recv():
    tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    address = (('192.168.110.128', 8080))
    tcp_socket.connect(address)
    while True:
        re_info = tcp_socket.recv(1024)
        print('接收:%s'%re_info.decode('utf-8'))
    tcp_socket.close()
if __name__ == '__main__':
    #定义发送的线程
    p1 = threading.Thread(target=tcp_send)
    # p1.setDaemon(True)
    #启动发送线程
    p1.start()
    # 定义接收的线程
    p2 = threading.Thread(target=tcp_recv)
    # p2.setDaemon(True)
    #启动接收线程
    p2.start()

这个程序实现了客户端与服务器之间的数据发送与接收,相当于一个简易的聊天器…

多线程共享全局变量:
from threading import Thread
import time
def work1(nums):
nums.append(44)
print("----in work1---",nums)
def work2(nums):
#延时, 保证t1线程中的事情做完
time.sleep(1)
print("----in work2---",nums)
g_nums = [11,22,33]
t1 = Thread(target=work1, args=(g_nums,))
t1.start()
t2 = Thread(target=work2, args=(g_nums,))
t2.start()

总结:
1.在一个进程内的所有线程共享全局变量, 能够在不适用其他方式的前提下完成多线程之间的数据共享(这点要比多进程要好)
缺点就是, 线程是对全局变量随意遂改可能造成多线程之间对全局变量的混乱(即线程非安全)

互斥锁
#提出问题:

假设两个线程t1和t2都要对num=0进行增1运算, t1和t2都各对num修改10次, num的最终的结果应该为20。但是由于是多线程访问, 有可能出现下面情况:
在num=0时, t1取得num=0。 此时系统把t1调度为”sleeping”状态, 把t2转换为”running”状态, t2也获得num=0。 然后t2对得到的值进行加1并赋给num,使得num=1。 然后系统又把t2调度为”sleeping”, 把t1转为”running”。 线程t1又把它之前得到的0加1后赋值给num。 这样, 明明t1和t2都完成了1次加1工作, 但结果仍然是num=1。

#怎么解决:
  1. 系统调⽤t1, 然后获取到num的值为0, 此时上一把锁, 即不允许其他现在操作num
  2. 对num的值进行+1
  3. 解锁, 此时num的值为1, 其他的线程就可以使用num了, 而且是num的值不是0而是1
  4. 同理其他线程在对num进⾏修改时, 都要先上锁, 处理完后再解锁, 在上锁的整个过程中不允许其他线程访问, 就保证了数据的正确性
#使用互斥锁解决该问题:
import threading
#引用互斥锁
mutex = threading.Lock()


num = 0

def work1(number):
    #当work1抢到资源时上锁
    mutex.acquire()
    global num
    for i in range(number):
        num += 1
    print('work1=',num)
    #执行完任务之后释放
    mutex.release()


def work2(number):
    #work2抢到资源时上锁
    mutex.acquire()
    global num
    for i in range(number):
        num += 1
    print('work2=', num)
    #执行完成之后释放
    mutex.release()


if __name__ == '__main__':
    #两个方法各相加100万次
    t1 = threading.Thread(target=work1,args=(1000000,))
    t2 = threading.Thread(target=work1,args=(1000000,))
    t1.start()
    t2.start()

总结
锁的好处:
确保了某段关键代码只能由一个线程从头到尾完整地执行
锁的坏处:
阻止了多线程并发执行, 包含锁的某段代码实际上只能以单线程模式执行, 效率就大大地下降了
由于可以存在多个锁, 不同的线程持有不同的锁, 并试图获取对方持有的锁时, 可能会造成死锁
解决死锁的方式:
程序设计时要尽量避免(银行家算法)
添加超时时间等

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值