python_learn Manager、线程、守护线程及相关函数

# ### Manager (list列表 , dict字典) 进程之间的共享数据(列表或者字典等)
from multiprocessing import Process,Manager,Lock

def work(data,lock):
	# 1.正常写法
	"""
	lock.acquire()
	# data["count"] -= 1
	data[0] += 1
	lock.release()
	"""

	# 2.使用with 语法简化上锁解锁操作
	with lock:
		data[0] += 1

if __name__ == "__main__":
	m = Manager()
	# 创建一个共享的字典
	data = m.dict( {"count":20000} )
	# 创建一个共享的列表
	data = m.list([1,2,3])

	# print(data)

	lst = []
	lock = Lock()
	for i in range(100):
		p = Process(target=work,args=(data,lock))
		p.start()
		lst.append(p)

	# 确保所有的进程执行完毕,然后在向下运行,打印数据,否则报错;
	for i in lst:
		i.join()

	print(data) # [101, 2, 3]

# 19900
# {'count': 19901}


# -----------------------------------------------------
#线程

# 进程是 划分资源 资源分配最小单位
# 线程 执行程序 是计算机中调度最小单位
# 多个线程 共享一份资源 进程

from threading import Thread
from multiprocessing import Process
import os,time

#(1) 一份进程资源中可以包含多个线程
def func(num):
    print("当前线程,所归属的进程id",os.getpid(),num)

for i in range(10)
    #(基于当前这个主进程创建了10个子线程,然后主线程本身就自带一个线程,一共11个)
    t = Thread(target=func,args=(i,)) #创建线程跟进程对象用法一样,返回一个线程对象
    t.start()

#(2) 并发的多进程和多线程,谁的速度更快
def func(num):
    print("当前线程,所归属的进程id",os.getpid(),num)

if __name__ == '__main__':
    #统计1000个线程的运行时间
    #记录时间
    starttime = time.time()
    lst = []
    for i in range(1000):
        t = Thread(target=func,args=(i,))
        t.start()
        lst.append(t)
    #确保所有线程执行完毕
    for i in lst:
        i.join()
    #结束时间
    endtime = time.time()
    print('执行的时间是{}'.format(endtime-starttime))

    #统计1000个进程的运行时间
    #记录时间
    starttime = time.time()
    lst = []
    for i in range(1000):
        p = Process(target=func,args=(i,))
        p.start()
        lst.append(p)
    #确保所有线程执行完毕
    for i in lst:
        i.join()
    #结束时间
    endtime = time.time()
    print('执行的时间是{}'.format(endtime-starttime)


#(3)多线程共享同一份进程资源
num = 1000
def func():
    global num
    num -= 1

for i in range(1000):
    t = Thread(target=func)
    t.start()

print(num)


# ------------------------------------------------

# 用类去定义线程
from threading import Thread

class MyThread(Thread):
	def __init__(self,name):
		# 手动调用父类的构造方法
		super().__init__()
		self.name = name

	def run(self):	# 这个名字不能乱写,必须是run
		print("当前进程正在执行running..",self.name)

if __name__ == "__main__":  # 无论线程进程,这句话必须加上
	t = MyThread("爆炸")
	t.start()
	print("主线程执行完毕")

# 为什么子线程比主线程执行速度要快了?因为不用额外建立空间了,没有什么阻塞,这个也是典型的异步程序. 都是异步并发
# 如果在子线程上加一个sleep,就会发现主线程先执行完毕了
# 进程是一片地,线程是这片地上的工人

# --------------------------------------------------

"""线程相关函数"""
"""
1.线程.is_alive()  检测线程是否仍然存在
2.线程.setName()	设置线程名字
3.线程.getName()	获取线程名字
4.currentThread().ident		查看线程id号
5.enumerate()	返回目前正在运行的线程列表
6.activeCount()	返回目前正在运行的线程数量
"""
from threading import Thread

def func():
	pass
if __name__ == "__main__":  # 无论线程进程,这句话必须加上
	t = Thread(target=func)
	print(t)
	t.start()
	print(t)
	print(t.is_alive()) 	# False
	print(t.get.Name())		# Thread-1
	t.setName("alex")
	print(t.getName)
# 如果加个sleep,最后会返回True,因为那时候主线程都执行完了
# 线程公用一个进程id,但每个线程也都有自己的线程id号

from threading import Thread
from threading import CurrentThread
from threading import enumerate
from threading import activeCount
import os,time

"""
def func():
	print("子线程id",currentThread().ident,os.getpid())
	# 子线程id 123145367060480 39988
if __name__ == "__main__":  # 无论线程进程,这句话必须加上
	Thread(target=func).start()
	print("主线程id",currentThread().ident,os.getpid())
	# 主线程id 140736045925248 39988
"""


def func():
	print("子线程id",currentThread().ident,os.getpid())
	time.sleep(0.5)

if __name__ == "__main__":  # 无论线程进程,这句话必须加上
	for i in range(10):
		Thread(target = func).start()
	lst = enumerate()
	# 子进程10个,主进程1个,一共11个
	print(lst, len(lst))		# 11
# enumerate 打印活着的线程

	print(activeCount())		# 11 这是第二个方法,一般都用enumerate
	print(obj)#

# enumerate 枚举  zip 拉链, 他俩返回的都是迭代器,返回的都是迭代器

# --------------------------------------------------

"""守护线程
等待所有线程全部执行完毕之后,再终止自己,它守护的是所有线程
"""
from threading import Thread
from threading import CurrentThread
from threading import enumerate
from threading import activeCount
import os,time

def func1():
	while True:
		time.sleep(0.5)
		print("我是func1")

def func2():
	print("我是func2 start")
	time.sleep(3)
	print("我是func2 end")


t1 = Thread(target=func1)
t2 = Thread(target=func2)

# 守护进程在start之前进行设置,主进程结束后,干掉守护的进程
# 守护线程的格式有点不一样
t1.setDaemon(True)	# 主线程执行完毕后,停止t1线程的运行
t1.start()
t2.start()

print("主线程执行结束")

# 线程里面套进程,进程再套线程,资源耗费会很大

# --------------------------------------------------

"""Lock 保证线程的数据安全"""
from threading import Lock,Thread

n = 0

def func1():
	global n
	for i in range(1000000):
		n -= 1
def func2():
	global n
	for i in range(1000000):
		n += 1
#
# func1()
# func2()
# print(n)

if __name__ == "__main__":
	lst = []
	# lock = Lock()	# 线程锁

	for i in range(10):
		t1 = Thread(target=func1)
		t2 = Thread(target=func2)
		t1.start()
		t2.start()
		lst.append(t1)
		lst.append(t2)

	for i in lst:
		i.join()

	print("主线程执行结束..",n)

"""
针对于一个线程有这么三步操作:第一步先把0取出来,第二步+1,把1算出来,第三步把计算好的值放回原空间
当有多个线程时,有可能第一个线程正在计算的过程中,还没等把结果放回去,第二个线程把0拿出来了,这就是把0拿出来了2次,造成了结果不准确.如果有更多的线程,那么就更乱了,导致数据完全不准确.
所以,针对异步处理数据,一定要加锁.加锁变成同步,即使慢,那也没办法.虽然慢,但肯定要比一个主线的同步要快

但经过实践,还是把锁放外面

"""
### 改进加锁
"""Lock 保证线程的数据安全"""
from threading import Lock,Thread

n = 0
# 加锁要加到哪个位置呢?放在循环里,上锁解锁频率变快
# 如果把锁写到外面,换锁的频率慢,如果抢到了,那就一定会把这些循环执行完才解锁,别的线程才能抢到.
# 所以还是放到里面比较好,这些线程都有机会抢到这把锁
def func1(lock):
	global n
	for i in range(1000000):
# 		上锁方法1
		lock.acquire()
		n -= 1
		lock.release()
def func2(lock):
	global n
	for i in range(1000000):
		# 上锁方法2
		with lock:
			n += 1
#
# func1()
# func2()
# print(n)

if __name__ == "__main__":
	lst = []
	lock = Lock()	# 线程锁

	for i in range(10):
		t1 = Thread(target=func1,args=(lock,))
		t2 = Thread(target=func2,args=(lock,))
		t1.start()
		t2.start()
		lst.append(t1)
		lst.append(t2)

	for i in lst:
		i.join()

	print("主线程执行结束..",n)

# ---------------
# 锁放到外面

def func1(lock):
	global n
	lock.acquire()
	for i in range(1000000):
# 		上锁方法1
		n -= 1
	lock.release()
def func2(lock):
	global n
	with lock:
		for i in range(1000000):
		# 上锁方法2
			n += 1
#
# func1()
# func2()
# print(n)

if __name__ == "__main__":
	lst = []
	lock = Lock()	# 线程锁

	for i in range(10):
		t1 = Thread(target=func1,args=(lock,))
		t2 = Thread(target=func2,args=(lock,))
		t1.start()
		t2.start()
		lst.append(t1)
		lst.append(t2)

	for i in lst:
		i.join()

	print("主线程执行结束..",n)


# --------------------------------------------------

# 信号量 Semaphore(线程)

from threading import Semaphore,Thread
import time

def func(i,sm):
	with sm:
		print(i)
		time.sleep(3)

if __name__ == "__main__":
	sm = Semaphore(5)
	for i in range(20):
		Thread(target=func,args=(i,sm)).start()

# 在创建线程的时候是异步创建,在执行任务的时候,因为Semaphore加了锁,所以线程之间变成了同步

# --------------------------------------------------

# 线程的缺陷:
# 线程可以并发,但是不能并行(多个cpu不停的运行多个程序),因为GIL锁(全局解释器锁,同一个进程下的多个线程,只能被一个cpu执行)
# 进程可以并发,并行执行
# 在java中,线程可以并行
# python是解释性语言,边编译边执行,不是一次性全部编译成功的,不能提前规划,都是临时调度容易造成cpu执行调度异常,所以加了一把锁叫GIL

# 想要并行的解决办法:
# 1.用多进程间接实现线程的并行
# 2.换一个Pypy,Jpython解释器

# 程序分为计算密集型和io密集型
# 对于计算密集型程序会过度依赖cpu,但网页,爬虫,oa办公,这种io密集型的程序里,python绰绰有余

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值