Python多线程使用及线程同步

多线程使用

  Python使用多线程有两种方式,函数式和用类来包装线程对象.

线程模块

  Python通过两个标准库thread和threading提供对线程的支持。thread提供了低级别的、原始的线程以及一个简单的锁。

  thread 模块提供的其他方法:

  • threading.currentThread(): 返回当前的线程变量。
  • threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
  • threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
  除了使用方法外,threading同样提供了Thread类来处理线程,Thread类提供了以下方法:
  • run(): 用以表示线程活动的方法。
  • start():启动线程活动。
  • join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。
  • isAlive(): 返回线程是否活动的。
  • getName(): 返回线程名。
  • setName(): 设置线程名。
  • isDaemon():一个布尔值,指示线程是(True)否(False)是一个守护线程。它必须在调用start()之前设置,否则会引发RuntimeError它的初始值继承自创建它的线程;主线程不是一个守护线程,所以在主线程中创建的所有线程默认daemon = False整个Python程序在没有活着的非守护进程时退出。

函数式实现

 方法一:

  调用thread模块中的start_new_thread方法来创建线程.
thread.start_new_thread ( function, args[, kwargs] )
  function是线程函数;args是传递给线程函数的参数,是一个tuple类型;kwargs是可选参数
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import thread
import time

def execute(thread_name, delay, counts):
    for i in range(counts):
        time.sleep(delay)
        print(" %s %s" % (thread_name, time.ctime(time.time())))

def main():
    try:
        thread.start_new_thread(execute, ('thread_1', 1, 3))
        thread.start_new_thread(execute, ('thread_2', 2, 3))
    except:
        print('cannot start thread')

if __name__ == '__main__':
    main()
    time.sleep(10)

 方法二

  使用threading.Thread()
threading.Thread(group=None, target=None, name=None, args=(), kwargs={})
        target就是线程函数,name是线程名,args是传给target的参数,kwargs是字典类型的参数

import threading
import time


def execute(delay, counts):
    for i in range(counts):
        time.sleep(delay)
        print("%s %s" % (threading.current_thread().name, time.ctime(time.time())))

def main():
    try:
        thread_1 = threading.Thread(target=execute, name='thread_1', args=(1, 3))
        thread_2 = threading.Thread(target=execute, name='thread_2', args=(2, 3))
    except:
        print('cannot start thread')
    thread_1.start()
    thread_2.start()
    thread_1.join()
    thread_2.join()

if __name__ == '__main__':
    main()

使用Threading模块创建

  使用Threading模块创建线程,继承threading.Thread,然后重写__init__方法和run方法:这种方式是推荐的方式.
import threading
import time

class MyThread(threading.Thread):
    """docstring for MyThread"""
    def __init__(self, thread_name, delay, counts):
        super(MyThread, self).__init__()
        self.thread_name = thread_name
        self.delay = delay
        self.counts = counts

    def run(self):
        for i in range(self.counts):
            time.sleep(self.delay)
            print('%s %s' % (self.thread_name, time.ctime(time.time())))

def main():
    thread_1 = MyThread('thread_1', 1, 3)
    thread_2 = MyThread('thread_2', 2, 3)
    thread_1.start()
    thread_2.start()

if __name__ == '__main__':
    main()

线程同步

  多个线程共享同一个资源就会存在线程安全问题, 两个或两个以上的线程需要共享资源,它们需要某种方法来确定资源在某一刻仅被一个线程占用。达到此目的的过程叫做同步(synchronization), 解决线程安全问题的方法就是利用同步机制.
import threading
import time


class Account(object):
    """docstring for Account"""
    def __init__(self, money):
        super(Account, self).__init__()
        self.money = money

    def withdraw(self, number):
        if number < 0:
            return -1
        elif self.money < 0:
            return -2
        elif number > self.money:
            return -3
        else:
            time.sleep(1)
            self.money -= number
            print('withdraw %d remain %d' % (number, self.money))
            return number


class User(threading.Thread):
    """docstring for MyThread"""
    def __init__(self, thread_name, account):
        super(User, self).__init__()
        self.thread_name = thread_name
        self.Account = account

    def run(self):
        self.get_money(800)

    def get_money(self, number):
        print('%s get %d' % (self.thread_name, self.Account.withdraw(number)))


def main():
    account = Account(1000)
    user_1 = User('User_1', account)
    user_2 = User('User_2', account)
    user_1.start()
    user_2.start()

if __name__ == '__main__':
    main()
  银行账户取款问题,两个用户使用同一个账户取款,比如一个人拿存折去银行取,一个人拿卡去取款机取,这是可能存在的.账户里总共有1000元,但是两个人都要取800,正常来说是一个人去了800后另外一个人是取不出的,但是运行的结果是:
withdraw 800 remain 200
User_1 get 800
withdraw 800 remain -600
User_2 get 800
  两个用户都取出了800.这是为什么呢?因为在钱数减少前休眠了一个简短的时间,可能一个用户进入休眠后,由于钱并为减少,所以另一个用户也能进入,所以两个用户都能取走钱.
  在threading模块中,可以使用Thread对象的Lock和Rlock可以实现简单的线程同步,这两个对象都有acquire方法和release方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到acquire和release方法之间。
import threading
import time

class Account(object):
    """docstring for Account"""
    def __init__(self, money):
        super(Account, self).__init__()
        self.money = money

    def withdraw(self, number):
        if number < 0:
            return -1
        elif self.money < 0:
            return -2
        elif number > self.money:
            return -3
        else:
            time.sleep(1)
            self.money -= number
            print('withdraw %d remain %d' % (number, self.money))
            return number

class User(threading.Thread):
    """docstring for MyThread"""
    def __init__(self, thread_name, account, lock):
        super(User, self).__init__()
        self.thread_name = thread_name
        self.Account = account
        self.thread_lock = lock

    def run(self):
        self.thread_lock.acquire()
        self.get_money(800)
        self.thread_lock.release()

    def get_money(self, number):
        print('%s get %d' % (self.thread_name, self.Account.withdraw(number)))

def main():
    threadLock = threading.Lock()
    account = Account(1000)
    user_1 = User('User_1', account, threadLock)
    user_2 = User('User_2', account, threadLock)
    user_1.start()
    user_2.start()

if __name__ == '__main__':
    main()
 运行结果:
withdraw 800 remain 200
User_1 get 800
User_2 get -3
 只有一个用户能取出钱.

你可能感兴趣的:(多线程,python)