python 线程基础

线程基础
# 线程基础
"""
多任务的概念:就是操作系统可以同时运行多个任务
并发:指的是任务数多余cpu核数,通过操作系统的各种任务调度算法,实现用多个任务“一起”执行(实际上总有一些任务不在执行,因为切换任务的速度相当快,看上去一起执行而已)
并行:指的是任务数小于等于cpu核数,即任务真的是一起执行的

python的thread模块是比较底层的模块,python的threading是高级模块

常用操作
threading.currentThread(): 返回当前的线程变量。
threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程
threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果
run(): 用以表示线程活动的方法
start():启动线程活动
join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生
isAlive(): 返回线程是否活动的
getName(): 返回线程名
setName(): 设置线程名

线程注意点
   使用threading模块时,往往会定义一个新的子类class,只要继承threading.Thread就可以了,然后重写run方法
   当线程的run()方法结束时该线程完成。
   多线程程序的执行顺序是不确定的  无法控制线程调度程序,但可以通过别的方式来影响线程调度的方式。
   每个线程默认有一个名字,python会自动为线程指定一个名字
   在一个进程内的所有线程共享全局变量,很方便在多个线程间共享数据
   线程是对全局变量随意遂改可能造成多线程之间对全局变量的混乱(即线程非安全)
   如果多个线程同时对同一个全局变量操作,会出现资源竞争问题,从而数据结果会不正确
   同步就是协同步调,按预定的先后次序进行运行。如:你说完,我再说。
   可理解为进程或线程A和B一块配合,A执行到一定程度时要依靠B的某个结果,于是停下来,示意B运行;B执行,再将结果给A;A再继续操作。


线程同步
   当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制
   使用 Thread 对象的 Lock 和 Rlock 可以实现简单的线程同步,这两个对象都有 acquire 方法和 release 方法
   对于那些需要每次只允许一个线程操作的数据,可以将其操作放到 acquire 和 release 方法之间
   线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁
   某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;
   直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。
   互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。

hreading模块中定义了Lock类,可以方便的处理锁定
    # 创建锁
    mutex = threading.Lock()
    # 锁定
    mutex.acquire()
    # 释放
    mutex.release()

锁的好处 确保了某段关键代码只能由一个线程从头到尾完整地执行
锁的坏处 阻止了多线程并发执行  可能会造成死锁

死锁
在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁
避免死锁
   程序设计时要尽量避免(银行家算法)
   添加超时时间等


"""

# 多线程创建方式一
import threading

# threading.Thread(target=函数)  传名称即可


def say():
    print("你好啊,python")


for i in range(5):
    t = threading.Thread(target=say)
    t.start()  # 当调用start()时,才会真正的创建线程,并且开始执行

# 主线程会等待所有的子线程结束后才结束
import threading
from time import sleep,ctime


def sing():
    for i in range(3):
        print("正在唱歌...%d" % i)
        sleep(1)


def dance():
    for i in range(3):
        print("正在跳舞...%d" % i)
        sleep(1)


if __name__ == '__main__':
    print('---开始---:%s' % ctime())

    t1 = threading.Thread(target=sing)
    t2 = threading.Thread(target=dance)

    t1.start()
    t2.start()

    sleep(5)  # 屏蔽此行代码,试试看,程序是否会立马结束?
    print('---结束---:%s' % ctime())

# 查看线程数量
import threading
from time import sleep,ctime

def sing():
    for i in range(3):
        print("正在唱歌...%d" % i)
        sleep(1)

def dance():
    for i in range(3):
        print("正在跳舞...%d" % i)
        sleep(1)

if __name__ == '__main__':
    print('---开始---:%s' % ctime())

    t1 = threading.Thread(target=sing)
    t2 = threading.Thread(target=dance)

    t1.start()
    t2.start()
    alength = threading.activeCount()
    print("活动线程数量是:%s" % alength)
    while True:
        # length = len(threading.enumerate())  # 返回一个包含正在运行的线程的list列表
        # print('运行的线程数为:%d' % length)
        # if length <= 1:
        #     break

        alength = threading.activeCount()
        print("活动线程数量是:%s" % alength)  # 返回正在运行的线程数量  threading.activeCount() == len(threading.enumerate())
        if alength <= 1:
           break

        sleep(0.5)

# 线程的执行顺序 不能确定
import threading
import time

class MyThread(threading.Thread):
    def run(self):
        for i in range(3):
            time.sleep(1)
            msg = "I'm "+self.name+' @ '+str(i)
            print(msg)
def test():
    for i in range(5):
        t = MyThread()
        t.start()
if __name__ == '__main__':
    test()

# 线程执行代码的封装
import threading
import time

class MysThread(threading.Thread):
    def run(self):
        for i in range(3):
            time.sleep(1)
            msg = "I'm "+self.name+' @ '+str(i)  # name属性中保存的是当前线程的名字
            print(msg)


if __name__ == '__main__':
    t = MysThread()
    t.start()

# 多线程数据是共享的
from threading import Thread
import time

g_num = 100

def work1():
    global g_num
    for i in range(3):
        g_num += 1

    print("----in work1, g_num is %d---"%g_num)


def work2():
    global g_num
    print("----in work2, g_num is %d---"%g_num)


print("---线程创建之前g_num is %d---"%g_num)

t1 = Thread(target=work1)
t1.start()

# 延时一会,保证t1线程中的事情做完
time.sleep(1)

t2 = Thread(target=work2)
t2.start()

# 互斥锁 -- 解决数据共享出现的问题
import threading
import time

g_num = 0

def test1(num):
    global g_num
    for i in range(num):
        mutex.acquire()  # 上锁
        g_num += 1
        mutex.release()  # 解锁

    print("---test1---g_num=%d"%g_num)

def test2(num):
    global g_num
    for i in range(num):
        mutex.acquire()  # 上锁
        g_num += 1
        mutex.release()  # 解锁

    print("---test2---g_num=%d"%g_num)

# 创建一个互斥锁
# 默认是未上锁的状态
mutex = threading.Lock()

# 创建2个线程,让他们各自对g_num加1000000次
p1 = threading.Thread(target=test1, args=(1000000,))
p1.start()

p2 = threading.Thread(target=test2, args=(1000000,))
p2.start()

# 等待计算完成
while len(threading.enumerate()) != 1:
    time.sleep(1)

print("2个线程对同一个全局变量操作之后的最终结果是:%s" % g_num)

# udp 聊天
import socket
import threading
# 接收信息
def recvs(udp_socket):
    while True:
        back = udp_socket.recvfrom(1024)
        msg = back
        print(msg)

# 发送信息
def sends(udp_socket, dest_ip, dest_port):
    while True:
        msg = input("请输入你要发送的信息:")
        if msg == 'exit':
            break
        udp_socket.sendto(msg.encode(), (dest_ip, dest_port))

# udp主函数
def main():
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_socket.bind(('', 8001))

    dest_ip = input("请输入对方的ip:")
    dest_port = int(input("请输入对方的port:"))

    t1 = threading.Thread(target=sends, args=(udp_socket, dest_ip, dest_port))
    t2 = threading.Thread(target=recvs, args=(udp_socket,))

    t1.start()
    t2.start()


if __name__ == '__main__':
    main()

 

posted @ 2019-12-12 13:38  微刻时光  阅读(194)  评论(0编辑  收藏  举报