Python/网络编程/多线程与多进程05

Thread类:


  Thread类是threading模块中最常用的功能,通过调用用户指定函数func,用于独立生成一个活动线程。调用用户指定函数func,可以有两种方法:一是在Thread创建实例对象时,把func以参数的形式传递给构造函数;二是通过继承Thread类重写run方法,调用func函数,在Thread的子类中,只允许__init__()run()方法进行重写。

Thread(group=None, target=None, name=None, args=(), kwargs=None, daemon=None)

  • group:用于保留,作为将来的扩展功能,可以忽略该参数,或设置group=none
  • target:设置线程需要执行的自定义函数,如target=func设置完成后被run()方法调用; 当target=none时,线程不执行任何操作。
  • name:指定需要执行的线程名称。不指定时,该类自动生成一个Thread-N形式的线程名称。
  • args:当自定义函数func带有参数时,把参数以元组的形式通过args传递给func
  • kwargs:当自定义函数的func带有参数时,把参数以字典的形式通过kwargs传递给func
  • daemon:当daemon不是none时,通过设置True&False确定是否守护进程。

Thread类的主要方法:

方法名称 使用描述
start() 线程启动状态(一个线程对象只能调用该方法一次),该方法必须在run()方法前被调用
run() 运行线程,使线程处于活动状态,在run()方法里执行指定的用户自定义函数func,该方法可以在Thread子类被重写
join(timeout=None) 阻塞调用线程。等待调用该方法的线程对象运行,一直到该线程执行终止,阻塞才释放。timeout为可选参数,可以设置阻塞时间(以秒为单位)当timeout参数不存在或者为none时,该操作将阻塞,直到线程终止。该方法运行在run()方法后
name 线程名称,初始名称由构造函数设置
is_alive() 返回线程是否存在
daemon 显示此线程是否为守护程序线程(True)或不(False)的布尔值。这必须在调用start() 之前设置,否则会引发runtimeError。

一旦一个线程对象被创建,其活动必须通过调用线程的start()方法来启动,然后调用run()方法执行指定的用户自定义函数func。join方法在run()方法后执行。这会阻塞调用线程,直到调用join方法的线程运行终止,才能执行后续的程序代码。

多线程加lock/1

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import time
import logging
import threading
from threading import Thread

logging.basicConfig(
    level=logging.DEBUG,
    format='%(threadName)-10s:%(message)s'
)

lock = threading.Lock()


def countdown(n):
    while n > 0:
        # print(f"线程名字为:{threading.current_thread().getName()},正在减数:{n}")
        logging.debug(f"正在减数:{n}")
        n -= 1
        time.sleep(1)


class MyThread(Thread):
    """Inherit the Thread class and override the run method
    The default Thread parameter is: Thread(group=None, target=None, name=None, args=(), kwargs=None, daemon=None)

    Because the run method in the Thread class can be rewritten,
    the other parameters are None, because there is a start method for inheritance, 
    the run method will be called when the start method is run, and the run is rewritten, and the function can be executed.
    """
    def __init__(self, Thread_name, count):
        Thread.__init__(self)
        self.Thread_name = Thread_name
        self.count = count
    
    def run(self):
        try:
            lock.acquire()
            logging.debug("加锁了.....")
            countdown(self.count) 
        finally:
            lock.release()
            logging.debug("锁被释放了....")


def main():
    """
    Thread(group=None, target=None, name=None, args=(), kwargs=None, daemon=None)
    A class that represents a thread of control.
    """

    Thread_list = []
    logging.debug('start')
    for i in range(3):
        t = MyThread(f'yankerp-{i+1}', 3)
        t.start()
        Thread_list.append(t)
    
    for i in Thread_list:
        i.join() # Wait until the thread terminates. # 终止

    logging.debug('stop')

if __name__ == "__main__":
    main()
>>>
MainThread:start
Thread-1  :加锁了.....
Thread-1  :正在减数:3
Thread-1  :正在减数:2
Thread-1  :正在减数:1
Thread-1  :被释放了....
Thread-2  :加锁了.....
Thread-2  :正在减数:3
Thread-2  :正在减数:2
Thread-2  :正在减数:1
Thread-2  :被释放了....
Thread-3  :加锁了.....
Thread-3  :正在减数:3
Thread-3  :正在减数:2
Thread-3  :正在减数:1
Thread-3  :被释放了....
MainThread:stop

多线程加lock/2

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import time
import logging
import random
import sys
import threading
from threading import Thread

logging.basicConfig(
    level=logging.DEBUG,
    format='%(threadName)-10s:%(message)s'
)

lock = threading.Lock()
all_list = []
count = 0


def add_plus():
    """This is a function that increments the number. Global defines all variables and can be modified in the add_plus function.

    It can be automatically locked by the with method, and can be automatically released when the operation ends.
    """
    global count
    # lock.acquire()
    with lock:
        logging.debug(f'增加之前的数为:{count}')
        wait = random.randint(1, 3)
        time.sleep(wait)
        print(f"执行了{wait}秒之后.....")
        count += 1
        logging.debug(f'增加之后的数位:{count}')
        # lock.release()


def main():
    for i in range(int(sys.argv[1])):
        t = Thread(target=add_plus)
        t.start()
        all_list.append(t)
    
    for i in all_list:
        i.join()

if __name__ == "__main__":
    main()
>>>
Thread-1  :增加之前的数为:0
执行了1秒之后.....
Thread-1  :增加之后的数位:1
Thread-2  :增加之前的数为:1
执行了1秒之后.....
Thread-2  :增加之后的数位:2
Thread-3  :增加之前的数为:2
执行了2秒之后.....
Thread-3  :增加之后的数位:3
Thread-4  :增加之前的数为:3
执行了1秒之后.....
Thread-4  :增加之后的数位:4
Thread-5  :增加之前的数为:4
执行了2秒之后.....
Thread-5  :增加之后的数位:5
Thread-6  :增加之前的数为:5
执行了2秒之后.....
Thread-6  :增加之后的数位:6
Thread-7  :增加之前的数为:6
执行了2秒之后.....
Thread-7  :增加之后的数位:7
Thread-8  :增加之前的数为:7
执行了3秒之后.....
Thread-8  :增加之后的数位:8
Thread-9  :增加之前的数为:8
执行了2秒之后.....
Thread-9  :增加之后的数位:9
Thread-10 :增加之前的数为:9
执行了3秒之后.....
Thread-10 :增加之后的数位:10

若不加lock
Python/网络编程/多线程与多进程05_第1张图片

多线程Rlock/3


#!/usr/bin/env python
# -*- coding:utf-8 -*-

import time
import logging
import random
import sys
import threading
from threading import Thread

logging.basicConfig(
    level=logging.DEBUG,
    format='%(threadName)-10s:%(message)s'
)

lock = threading.Lock()
all_list = []
count = 0


def add_plus2():
    global count
    with lock:
        count += 2


def add_plus():
    """This is a function that increments the number. Global defines all variables and can be modified in the add_plus function.

    It can be automatically locked by the with method, and can be automatically released when the operation ends.
    """
    global count
    # lock.acquire()
    with lock:
        logging.debug(f'增加之前的数为:{count}')
        wait = random.randint(1, 3)
        time.sleep(wait)
        print(f"执行了{wait}秒之后.....")
        count += 1
        logging.debug(f'增加之后的数位:{count}')
        add_plus2()
        # lock.release()


def main():
    for i in range(int(sys.argv[1])):
        t = Thread(target=add_plus)
        t.start()
        all_list.append(t)
    
    for i in all_list:
        i.join()

if __name__ == "__main__":
    main()

Python/网络编程/多线程与多进程05_第2张图片
Python/网络编程/多线程与多进程05_第3张图片

给lock+R即可解决
Python/网络编程/多线程与多进程05_第4张图片

Factory function that returns a new reentrant lock.A reentrant lock must be released by the thread that acquired it. Once a thread has acquired a reentrant lock, the same thread may acquire it again without blocking; the thread must release it once for each time it has acquired it.

(返回新重入锁的工厂函数。必须由获取它的线程释放重入锁。 一旦线程获得了可重入锁,同一个线程可以再次获取它而不会阻塞; 线程必须在每次获取它时释放一次。)
Python/网络编程/多线程与多进程05_第5张图片

你可能感兴趣的:(Python)