线程和进程
有时候我们需要同时执行多个任务,可以使用多线程也可以使用多进程。
进程是由若干线程组成的,一个进程至少有一个线程。线程是操作系统执行的基本单元,进程是资源的集合。每个进程都有一个单独的内存空间,是一个独立程序的一次运行活动。也就是说多个进城之间是不共享数据的。我们在windows的任务管理器中,就可以查看到很多应用的进程。线程是进程中的执行调度单位,一个进程中可以有一个或者多个线程在执行。这些线程共享进程中的所有资源。python提供了两个模块支持线程。_thread和threading._thread比较低级,一般建议使用threading。
threading线程实现
直接看代码:
import queue
import threading
import time
class myThread(threading.Thread):
def __init__(self,name):
threading.Thread.__init__(self)
self.name = name
def run(self):
#线程同步等待1秒钟,
time.sleep(1)
print("mythread")
thread1 = myThread("hello")
thread1.start()
#thread1加入当前线程, 当前线程等待thread1线程执行完毕后再继续执行。
thread1.join()
print("mainthread")
输出结果如下:
mythread
mainthread
线程同步
上面提到了,多个线程是共享进程的资源的。多个线程又是同时执行的。那么问题就来了
举一个经典的例子:比如你有一个银行账号里存者100块钱。你用吃完饭要用支付宝支付20元,这个支付过程分3步走,
1.1:查询账户100元
1.2:100 - 20 = 80
1.3:更改账户余额为80元
但是就是你刚执行到第2步的时候,歇了一会儿,这时候你媳妇拿着银行卡去存50元钱,也分三步走
2.1:查询账户100元
2.2:100 + 50 = 150
2.3:更改账户余额为150元
你媳妇执行到第二步的时候,也歇了一会儿,这时候你执行了第三步,然后你媳妇也执行了第三步。这时候你的银行卡里就有150块钱,你白白吃了一顿饭。
模拟代码如下:
import queue
import threading
import time
#账户类
class Account():
def __init__(self,num):
self.num = num
#自己
class Myself(threading.Thread):
def __init__(self,account):
threading.Thread.__init__(self)
self.account = account
#消费20元
def run(self):
#查询账户余额
num = self.account.num
#支付20元
num = num - 20
#模拟歇一会儿
time.sleep(1)
#改变账户余额
self.account.num = num
#媳妇
class Wife(threading.Thread):
def __init__(self,account):
threading.Thread.__init__(self)
self.account = account
#存50元
def run(self):
#查询账户余额
num = self.account.num
#存50元
num = num + 50
#模拟歇一会儿
time.sleep(2)
#改变账户余额
self.account.num = num
#创建锁
threadLock = threading.Lock()
#创建账户
account = Account(100)
#创建线程
thread1 = Myself(account);
thread2 = Wife(account);
thread1.start()
thread2.start()
#等待线程结束
ts = (thread1,thread2)
for t in ts:
t.join()
print(account.num)
输出结果如下:
150
当然银行是不允许这种情况发生的。那么怎么解决呢?那就是你在支付的过程中,把账户锁住,不允许其他人操作此账户,待你操作完成之后,其他人才能操作。这个锁住的过程就是线程同步。修改代码:
import queue
import threading
import time
#账户类
class Account():
def __init__(self,num):
self.num = num
#自己
class Myself(threading.Thread):
def __init__(self,account):
threading.Thread.__init__(self)
self.account = account
#消费20元
def run(self):
#加上锁
threadLock.acquire()
#查询账户余额
num = self.account.num
#支付20元
num = num - 20
#模拟歇一会儿
time.sleep(1)
#改变账户余额
self.account.num = num
#释放锁
threadLock.release()
#媳妇
class Wife(threading.Thread):
def __init__(self,account):
threading.Thread.__init__(self)
self.account = account
#存50元
def run(self):
#加上锁
threadLock.acquire()
#查询账户余额
num = self.account.num
#存50元
num = num + 50
#模拟歇一会儿
time.sleep(2)
#改变账户余额
self.account.num = num
#释放锁
threadLock.release()
#创建锁
threadLock = threading.Lock()
#创建账户
account = Account(100)
#创建线程
thread1 = Myself(account);
thread2 = Wife(account);
thread1.start()
thread2.start()
#等待线程结束
ts = (thread1,thread2)
for t in ts:
t.join()
print(account.num)
输出结果如下:
130
condition
Python提供的Condition对象提供了对复杂线程同步问题的支持。Condition被称为条件变量,除了提供与Lock类似的acquire和release方法外,还提供了wait和notify方法。线程首先acquire一个条件变量,然后判断一些条件。如果条件不满足则wait;如果条件满足,进行一些处理改变条件后,通过notify方法通知其他线程,其他处于wait状态的线程接到通知后会重新判断条件。不断的重复这一过程,从而解决复杂的同步问题。下面我们使用condition来实现一个线程安全的队列,使用这个队列来实现经典的生产者消费者问题。
import queue
import threading
import time
#同步队列
class ConcurrentQueue():
def __init__(self,size):
self.__size = size #队列容量
self.__lock = threading.Lock() #锁
self.__condition = threading.Condition(self.__lock)
self.__queue = queue.Queue()
def get(self):
#是否获得锁成功
if self.__condition.acquire():
#如果队列为空,那么线程等待
if self.__queue.empty():
self.__condition.wait()
#取得结果
result = self.__queue._get()
#唤醒其他等待线程
self.__condition.notifyAll()
#释放锁
self.__condition.release()
return result;
def put(self,element):
#是否获得锁成功
if self.__condition.acquire():
#如果队列已满则等待
if self.__queue.qsize() >= self.__size:
self.__condition.wait()
#存入数据
self.__queue.put(element)
#唤醒其他线程
self.__condition.notifyAll()
#释放锁
self.__condition.release()
#生产者
class Produce(threading.Thread):
def __init__(self,queue):
threading.Thread.__init__(self)
self.__queue = queue
self.__num = 0
def run(self):
while True:
print("生产:"+str(self.__num))
self.__queue.put(self.__num)
self.__num += 1
time.sleep(2)
#消费者
class Consumer(threading.Thread):
def __init__(self,queue):
threading.Thread.__init__(self)
self.__queue = queue
def run(self):
while True:
element = self.__queue.get()
print("消费:"+str(element))
time.sleep(1)
q = ConcurrentQueue(10)
t1 = Produce(q)
t2 = Consumer(q)
t1.start()
t2.start()
输出结果如下:
生产:0
消费:0
生产:1
消费:1
生产:2
消费:2
生产:3
消费:3
生产:4
消费:4
生产:5
消费:5
.......