多线程(学习笔记)

1. 基础语法

import threading#导入多线程模块
from time import sleep

def loop(output):
    print(f'thread {threading.current_thread().name} is running...')#MainThread
    n=0
    while n<5:
        n=n+1
        print(f'thread {threading.current_thread().name}>>{n} {output}')

        sleep(1)
    print(f'thread {threading.current_thread().name} is end')

print(f'thread {threading.current_thread().name} is running...')
t=threading.Thread(target=loop,name='Loopthread',args=("Hello",))#分配线程任务 !!注意:args接收元组。如果不在"Hello"后面加上逗号,会被误以为是字符串序列。!!
t.start()#启用线程
t.join()#回收线程
print(f'thread {threading.current_thread().name} is end')#MainThread

2. 死循环与CPU占用

import threading

def Endless_loop():#死循环会严重占用CPU资源,是利用率达到100%,但Python中存在全局锁,可以让cpu处理其他线程
    print(f'Thread {threading.current_thread().name} is running...')
    n=1
    while True:
        n=n+1

t=threading.Thread(target=Endless_loop,name='Endless_loop')
t.start()

3. 线程锁

balance=0
Lock=threading.Lock()#初始化锁

def func(n):
    global balance
    balance=balance+n
    balance=balance-n

def Lock_test(n):
    for i in range(20000000):
        Lock.acquire()#请求锁
        try:
            func(n)
        finally:
            Lock.release()#释放锁

t1=threading.Thread(target=Lock_test,name='Lock_test',args=(5,))
t2=threading.Thread(target=Lock_test,name='Lock_test',args=(8,))
t1.start()
t2.start()
t1.join()
t2.join()
print(balance)

4. 本地局部变量Local

import threading

# 创建全局ThreadLocal对象:
local_school = threading.local()


def process_student():
    # 获取当前线程关联的student:
    std = local_school.student
    print('Hello, %s (in %s)' % (std, threading.current_thread().name))


def process_thread(name):
    # 绑定ThreadLocal的student:
    local_school.student = name
    process_student()


t1 = threading.Thread(target=process_thread, args=('Alice',), name='Thread-A')
t2 = threading.Thread(target=process_thread, args=('Bob',), name='Thread-B')
t1.start()
t2.start()
t1.join()
t2.join()

5. 线程池

如果不设置线程池,可能导致线程的无线增加

from concurrent.futures import ThreadPoolExecutor#导入线程池模块
import threading
from time import sleep
def func(max):
    my_sum=0
    for i in range(max):
        print(threading.current_thread().name+' '+str(i))
        my_sum=my_sum+i
    return my_sum

pool=ThreadPoolExecutor(max_workers=10)#创建10线程的线程池

thread1=pool.submit(func,20)#向线程池提交任务1
thread2=pool.submit(func,30)#向线程池提交任务2

result1=thread1.result()#获取线程的运行结果
result2=thread2.result()#获取线程的运行结果

#result()会等待线程执行完毕才执行

print(thread1.done())
# 判断future2代表的任务是否结束
print(thread2.done())
# 查看future1代表的任务返回的结果

#done()不会等待线程执行结束才执行,会输出True 或False

print(result1,result2)
pool.shutdown()#关闭线程池

此外,起始有更加巧妙的写法

##
#导入模块等操作
#定义功能函数等操作
##

with ThreadPoolExecutor(max_workers=5) as executor:#使用with...open可以保证线程池自动回收,简化代码
    # 提交任务给线程池
    thread_ids = [1, 2, 3, 4, 5]
    resluts=executor.map(func, thread_ids)#使用map进行分配任务,很巧妙!
    print(list(resluts))#解包可迭代对象

6. 总结

  1. 多线程编程,模型复杂,容易发生冲突,必须用锁加以隔离,同时,又要小心死锁的发生。

  2. Python解释器由于设计时有GIL全局锁,导致了多线程无法利用多核。多线程的并发在Python中就是一个美丽的梦。

  3. 多线程在Python中适合用于IO密集型任务

posted @ 2024-02-05 01:06  wyuu101  阅读(6)  评论(0编辑  收藏  举报