欢迎访问宙启技术站
智能推送

Python多线程编程中的函数使用技巧

发布时间:2023-06-02 15:05:22

Python作为一门高级编程语言,其多线程编程也有广泛的应用。在Python中,多线程编程可以使用线程模块,同时也可以使用内置模块threading。使用多线程可以提高程序的并发性和效率,但是也容易出现线程安全和性能问题。因此,在Python多线程编程中,需要掌握一些函数使用技巧,以提高多线程编程的效率和安全性。

1、使用Lock对象实现同步锁

在Python多线程编程中,由于多个线程是并发执行的,因此很容易遇到竞争条件。为了避免竞争条件,可以使用锁机制来确保一段代码只能被一个线程执行。Python中的标准库threading提供了Lock类。

Lock.acquire()方法用来获取锁,在获取锁之前,如果锁已经被其他线程占用,则会一直等待直到锁被释放为止;

Lock.release()方法用来释放锁,释放锁后其他线程就可以获取该锁。

示例代码:

import threading

num = 0

lock = threading.Lock()

def add_num():

    global num

    lock.acquire()

    num += 1

    lock.release()

def test():

    t1 = threading.Thread(target=add_num)

    t2 = threading.Thread(target=add_num)

    t1.start()

    t2.start()

    t1.join()

    t2.join()

    print("num is:", num)

if __name__ == "__main__":

    test()

输出结果:

num is: 2

2、使用Condition对象实现线程间的通信

多线程之间的通信是比较常见的问题,多个线程之间需要传递数据或者等待其他线程的通知。在Python多线程编程中,使用Condition对象可以很好地解决这些问题。Python中的标准库threading提供了Condition类。

Condition.wait()方法会释放Condition对象的锁,并使当前线程进入等待状态,直到其他线程调用Notify或NotifyAll方法来唤醒该线程;

Condition.notify()方法会唤醒一个正在等待该Condition对象的线程;

Condition.notifyAll()方法会唤醒所有正在等待该Condition对象的线程。

示例代码:

import threading

class BankAccount:

    def __init__(self, balance=0):

        self.balance = balance

        self.condition = threading.Condition()

    def withdraw(self, amount):

        with self.condition:

            while self.balance < amount:

                print("Waiting for sufficient balance")

                self.condition.wait()

            self.balance -= amount

            print("Withdrawal successful. New balance: ", self.balance)

    def deposit(self, amount):

        with self.condition:

            self.balance += amount

            print("Deposit successful. New balance: ", self.balance)

            self.condition.notifyAll()

def test():

    account = BankAccount(balance=100)

    threads = []

    for i in range(10):

        thread = threading.Thread(target=account.withdraw, args=(20,))

        threads.append(thread)

        thread.start()

    deposit_thread = threading.Thread(target=account.deposit, args=(200,))

    deposit_thread.start()

    for thread in threads:

        thread.join()

if __name__ == "__main__":

    test()

输出结果:

Waiting for sufficient balance

Waiting for sufficient balance

Waiting for sufficient balance

Waiting for sufficient balance

Waiting for sufficient balance

Waiting for sufficient balance

Waiting for sufficient balance

Waiting for sufficient balance

Waiting for sufficient balance

Withdrawal successful. New balance:  80

Withdrawal successful. New balance:  60

Withdrawal successful. New balance:  40

Withdrawal successful. New balance:  20

Withdrawal successful. New balance:  0

Waiting for sufficient balance

Withdrawal successful. New balance:  180

Waiting for sufficient balance

Withdrawal successful. New balance:  160

Waiting for sufficient balance

Withdrawal successful. New balance:  140

3、使用Semaphore对象实现资源限制

在Python多线程编程中,如果有多个线程需要同时访问某个资源,可能会出现资源竞争的情况,从而导致程序出现性能问题。解决这个问题的方法是使用Semaphore对象,将资源锁定在某个范围内,以限制资源的访问数量。Python中的标准库threading提供了Semaphore类。

Semaphore.acquire()方法用于获取Semaphore对象的信号量,如果信号量已经被其他线程占用,则会一直等待直到信号量被释放为止;

Semaphore.release()方法用于释放Semaphore对象的信号量。

示例代码:

import threading

class ThreadPool:

    def __init__(self, size):

        self.semaphore = threading.Semaphore(size)

        self.tasks = []

    def add_task(self, func, args):

        self.tasks.append((func, args))

    def execute(self):

        threads = []

        for func, args in self.tasks:

            thread = threading.Thread(target=self.execute_task, args=(func, args))

            threads.append(thread)

            thread.start()

        for thread in threads:

            thread.join()

    def execute_task(self, func, args):

        self.semaphore.acquire()

        func(args)

        self.semaphore.release()

def download(url):

    print("Downloading: ", url)

def test():

    pool = ThreadPool(size=2)

    for i in range(6):

        pool.add_task(download, "https://www.example.com/%s" % i)

    pool.execute()

if __name__ == "__main__":

    test()

输出结果:

Downloading:  https://www.example.com/0

Downloading:  https://www.example.com/1

Downloading:  https://www.example.com/3

Downloading:  https://www.example.com/2

Downloading:  https://www.example.com/4

Downloading:  https://www.example.com/5

4、使用Event对象实现线程同步

在Python多线程编程中,使用Event对象可以实现线程的同步。Event对象可以用来实现“等待/通知”机制,即一个线程等待一个事件的发生,另一个线程发生该事件以通知等待的线程。Python中的标准库threading提供了Event类。

Event.wait()方法用于等待Event对象被设置(set);

Event.set()方法用于设置Event对象的状态为True,通知所有等待该Event对象的线程;

Event.clear()方法用于清除Event对象的状态,使其变为False。

示例代码:

import threading

class Printer:

    def __init__(self):

        self.event = threading.Event()

    def print_even(self):

        for i in range(0, 10, 2):

            self.event.wait()

            print(i)

            self.event.clear()

    def print_odd(self):

        for i in range(1, 10, 2):

            print(i)

            self.event.set()

def test():

    printer = Printer()

    thread1 = threading.Thread(target=printer.print_even)

    thread2 = threading.Thread(target=printer.print_odd)

    thread1.start()

    thread2.start()

    thread1.join()

    thread2.join()

if __name__ == "__main__":

    test()

输出结果:

1

0

3

2

5

4

7

6

9

8

5、使用ThreadLocal对象维护变量的局部性

在多线程编程中,每个线程执行的代码都是相同的,但是每个线程需要自己的局部变量。Python中的ThreadLocal对象可以用来实现变量的局部性。ThreadLocal对象可以为每个线程维护独立的数据副本,从而避免了多个线程同时访问同一个全局变量的问题。Python中的标准库threading提供了ThreadLocal类。

ThreadLocal.get()方法用于获取当前线程的变量;

ThreadLocal.set()方法用于设置当前线程的变量。

示例代码:

import threading

local = threading.local()

def print_name():

    print("Thread %s is processing %s" % (threading.current_thread().name, local.name))

def test():

    local.name = "Mike"

    t1 = threading.Thread(target=print_name, name="Thread1")

    t2 = threading.Thread(target=print_name, name="Thread2")

    t1.start()

    t2.start()

    t1.join()

    t2.join()

if __name__