线程

时间:2019-12-14
本文章向大家介绍线程,主要包括线程使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

参考链接:  https://www.cnblogs.com/Eva-J/articles/8306047.html

threading

单线程

import time
from threading import Thread


def func(n):
    time.sleep(1)
    print(n)


if __name__ == "__main__":
    
    # 创建一个子线程
    t = Thread(target=func, args=(1,))
    t.start()

多线程

 主线程会等子线程执行完毕后再结束

import time
from threading import Thread

# 多线程并发

def func(n):
    time.sleep(5)
    print('我是子线程',n)


for i in range(10):

    # 主线程会等子线程执行完毕后再结束
    t = Thread(target=func, args=(i,))
    t.start()
    print('我是主线程')

类方法使用线程

import time
from threading import Thread

# 多线程并发

class MyTread(Thread):
    # 要使用新属性时需要调用父类的init
    def __init__(self,args):
        super().__init__()
        self.args = args

    # 一定要创建一个类方法
    def run(self):
        time.sleep(1)
        print(self.args)


t = MyTread(10)
t.start()

ps:

#进程是最小的内存分配单位。

#线程是 操作系统调度的最小单位。
#线程被CPU执行了。
#进程内至少含有一个线程。
#进程中可以开启多个线程。
#开启一个线程所需要的时间要远远小于开启一个进程。
#多个线程内部有自己的数据栈,数据不共享。
#全局变量在多个线程之间是共享的。
#在Cpython解释器下的python程序 在同一时刻 多个线程中只能有一个线程被CPU执行。GIL锁(全局解释器锁)
#高CPU :计算类——高CPU利用率。
#高IO  :爬取网页 200个网页
#qq聊天  send  recv  处理日志文件 读文件 处理web请求 读数据库

全局变量在多线程中是共享的 

import time
import os
from threading import Thread

# 多线程并发

def func(a, b):
    global g
    g = 0

    n = a + b


# 调用这个子线程之后,由于他声明了全部变量 所以这个g = 0
g = 100
lst = []

for i in range(1):
    # 开启一个子线程
    t = Thread(target=func, args=(i, 5))
    t.start()

    # 我这里只是为了取一个循环次数
    lst.append(t)

for t in lst:
    # 等子线程 执行完之后再执行 主线程
    t.join()
    
    #全局变量在线程之间是共享的
    print('主线程', g)

多进程和多线程时间对比

这差距不是一般的大呀!!!!

线程socket可以连接多个client

 client

线程模块中的其他方法

# 查看当前活跃线程数加上主线程  #10 +
print(threading.active_count())

# 查看是否属于主线程还是子线程
print(threading.current_thread())

# 显示所有线程名和id
print(threading.enumerate())
# get_ident 是查看线程id
print(threading.get_ident())

import time
import os
from threading import Thread
import threading

# 多线程并发

def func(n):
    time.sleep(0.5)

    # 查看是否属于主线程还是子线程
    print(i,threading.current_thread())

    # get_ident 是查看线程id
    print(threading.get_ident())

for i in range(10):
    t = threading.Thread(target=func,args=(i,))
    t.start()

# 查看当前活跃线程数加上主线程  #10 +
print(threading.active_count())

# 查看是否属于主线程还是子线程
print(threading.current_thread())

# 显示所有线程名和id
print(threading.enumerate())

守护线程

#守护进程随着主线程程代码的执行结束而结束。
#守护线程会在主线程执行完之后等待其他子线程的结束才结束。
#主线程在执行完自己的代码之后不会立即结束 而是等待子线程结束之后 回收子线程的资源。

import time
from threading import Thread

def func1():
    while 1 :
        time.sleep(1)
        print("\033[31m ******我还活着呢\033[0m")

def func2():
    time.sleep(10)
    print("我他吗是 func2")

if __name__ =='__main__':
    t1 = Thread(target=func1)

    # 定义一个守护线程(主线程结束之后 等待其他子线程的结束才结束 守护线程随之结束)
    t1.daemon = True
    t1.start()

    t2 = Thread(target=func2)
    t2.start()
    print("主线程")

线程锁(互斥锁)

数据不安全问题:

 

#10个线程同时开起来 同时去拿n = 10,拿回来之后隔了0.2秒才回来。
#在拿回来的过程当中别人都去拿,都拿的10,赋值回去了就是9
from threading import Lock, Thread
import time


# 死锁问题
def func():
    global n

    temp = n
    time.sleep(0.1)
    n = temp - 1

n = 10
lst = []

for i in range(10):
    t = Thread(target=func, args=())
    t.start()
    lst.append(t)

# 等待子线程执行完毕之后我再执行
t.join()
for i in lst:
    print(n)
0.2秒钟做的事情 

解决数据不安全问题

加锁

from threading import Lock
from threading import Thread
import time


# 死锁问题
def func(lock):
    global n

    # 拿钥匙 保证数据安全
    lock.acquire()

    temp = n
    time.sleep(0.1)
    n = temp - 1

    # 还钥匙 保证数据安全
    lock.release()


n = 10
lst = []
lock = Lock()
for i in range(10):

    t = Thread(target=func, args=(lock,))
    t.start()
    lst.append(t)

# 等待子线程执行完毕之后我再执行
t.join()
for i in lst:
    print(n)

科学家吃面现象(死锁问题)

只有一把钥匙,如果你要是同时,不管在一个进程里,还是在多个进程之间,你想拿多个钥匙就不行了。

from threading import Lock
from threading import Thread
import time

# 定义一个面条锁
noodle_lock = Lock()

# 定义一个叉子锁
fork_lock = Lock()


def eat1(name):
    # 加面条锁
    noodle_lock.acquire()
    print("\033[31m %s 拿到面条了\033[0m" % name)

    # 加勺子锁
    fork_lock.acquire()
    print('%s 拿到叉子了' % name)
    print('%s 吃面' % name)

    # 释放勺子锁
    fork_lock.release()

    # 释放面条锁
    noodle_lock.release()


def eat2(name):
    # 加勺子锁
    fork_lock.acquire()
    print('%s 拿到叉子了' % name)
    
    # 在停顿的时候黄埔也过去拿了面条,由于没有钥匙了 所以就停住了
    time.sleep(1)

    # 加面条锁
    noodle_lock.acquire()
    print("\033[31m %s 拿到面条了\033[0m" % name)
    print('%s 吃面' % name)

    # 释放勺子锁
    fork_lock.release()

    # 释放面条锁
    noodle_lock.release()


Thread(target=eat1, args=('Riven',)).start()

Thread(target=eat2, args=('Mark',)).start()

Thread(target=eat1, args=('黄埔',)).start()

Thread(target=eat2, args=('汨汨',)).start()

解决死锁问题(递归锁

同一个线程里拿多少次钥匙都可以,但又一个人拿到了这一串钥匙别的人就再也拿不到了。

from threading import RLock

# RLock = 一串钥匙
rlock = RLock()

rlock.acquire()
rlock.acquire()
rlock.acquire()
rlock.acquire()
rlock.acquire()
rlock.acquire()
rlock.acquire()
rlock.acquire()
rlock.acquire()

print('123')
from threading import Thread
from threading import RLock
import time



# 一个钥匙串 2 把钥匙
fork_lock = noodle_lock = RLock()


def eat1(name):
    # 我拿了一把钥匙,就一串钥匙在我手上
    noodle_lock.acquire()
    print("\033[31m %s 拿到面条了\033[0m" % name)


    fork_lock.acquire()
    print('%s 拿到叉子了' % name)
    print('%s 吃面' % name)

    # 等我把这一串钥匙都还了,下个人才能进来 就不会出现阻塞现象
    fork_lock.release()

    # 等我把这一串钥匙都还了,下个人才能进来 就不会出现阻塞现象
    noodle_lock.release()


def eat2(name):
    # # 我拿了一把钥匙,就一串钥匙在我手上
    fork_lock.acquire()
    print('%s 拿到叉子了' % name)

    time.sleep(1)

    noodle_lock.acquire()
    print("\033[31m %s 拿到面条了\033[0m" % name)
    print('%s 吃面' % name)

    # 等我把这一串钥匙都还了,下个人才能进来 就不会出现阻塞现象
    fork_lock.release()

    # 等我把这一串钥匙都还了,下个人才能进来 就不会出现阻塞现象
    noodle_lock.release()


Thread(target=eat1, args=('Riven',)).start()

Thread(target=eat2, args=('Mark',)).start()

Thread(target=eat1, args=('黄埔',)).start()

Thread(target=eat2, args=('汨汨',)).start()

信号量(Semaphore

事件

False状态

Wait()         false时阻塞

Wait()         ture时非阻塞

Clear                   False状态修改为False

Set                       False状态修改为True

例子

(连接数据库,检测数据库的可连接情况)

数据库---文件夹:

1.能够更方便的对数据进行增删改查

2.安全访问的机制

条件(Condition)

一个条件被创建之初默认有一个False状态。

False 状态会影响wait一直处于等待状态。

notifyint数据类型)制造几把钥匙。有几把钥匙就执行几次

from threading import Thread
from threading import Condition


def func(con, i):
    con.acquire()

    # 等钥匙,也就是说你有几把钥匙,就执行几次
    con.wait()
    print("\033[31m 在第 %s 个循环里\033[0m" % i)

    con.release()


con = Condition()

for i in range(10):
    Thread(target=func, args=(con, i)).start()

while 1:
    num = int(input('>>>>'))

    con.acquire()
    con.notify(num)  # 造钥匙
    con.release()

线程定时器(Timer)

import time
from threading import Timer


def func():
    print('时间同步')


while True:
    t = Timer(5, func).start()
    # 需要定义一个延时时间
    time.sleep(3)

队列

# 进程队列 先进先出

import queue

# 进程队列 先进先出
q = queue.Queue()

# 先进先出
# q.put(1)
# q.put(2)

q.put_nowait(1)
q.put_nowait(2)

# get_nowait 不会阻塞 会抛错
print(q.get_nowait())
print(q.get_nowait())
print(q.get_nowait())

# get 会阻塞
# print(q.get())
# print(q.get())

栈 先进后出

import queue

# 栈 先进后出
q = queue.LifoQueue()

q.put(1)
q.put(2)
q.put(3)

print(q.get())
print(q.get())
print(q.get())
print(q.get())

优先级队列(按照值的大小进行排序 从小到大)

import queue

# 优先级队列(按照值的大小进行排序 从小到大)
q = queue.PriorityQueue()

q.put(20)
q.put(50)
q.put(25)
q.put(40)

print(q.get())
print(q.get())
print(q.get())
print(q.get())

线程池(ThreadPoolExecutor)

import time
from concurrent.futures import ThreadPoolExecutor


def func(n):
    print(n)
    time.sleep(1)
    return n * 10


t_lst = []

# 定义一个线程池(默认 不要超过cup个数*5)
tpool = ThreadPoolExecutor(max_workers=5)

for i in range(20):

    # 传值(开启20个子线程)
    t = tpool.submit(func, i)
    t_lst.append(t)

# 相当于 close + join
tpool.shutdown()

print("主线程")

for t in t_lst:
    # t.result() 接受返回值
    print("\033[31m ==== \033[0m", t.result())

如果接受不到 返回值

在自定义函数中接受返回值

原文地址:https://www.cnblogs.com/Rivend/p/12040470.html