python线程问题、深浅拷贝、属性动态设置、迭代器iter、生成器yield
一、发现之前没有线程的日志,写了一个简单的,参考来源:https://www.cnblogs.com/vamei/archive/2012/10/11/2720042.html
import threading def demo(i): print("线程名",i) try: i = 0 # 开启线程数目 tasks_number = 10 print('测试启动') ths = [] # threadLock = threading.Lock() while i < tasks_number: # target:运行目标内容, name:线程名 ,这里的args会作为target入参 t = threading.Thread(target=demo,name=f"线程{i}",args=(i,)) ths.append(t) i += 1 for i in ths: i.start() for i in ths: i.join() print("退出线程") except Exception as e: print(e)
线程池
1、创建合理的线程数量,重用存在的线程,减少线程创建销毁带来的开销。
2、可有效的控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
3、提供定时执行、定期执行、单线程、并发数控制等功能。
import time from concurrent.futures import ThreadPoolExecutor, wait, FIRST_COMPLETED, as_completed def work(n): time.sleep(n) return n if __name__ == '__main__': # max_workers表示最多工作的线程数 executor = ThreadPoolExecutor(max_workers=10) # 提交线程需要执行的任务到线程池中,并返回该任务的句柄,注意submit()不是阻塞的,而是立即返回的 t1 = executor.submit(work, 4) t2 = executor.submit(work, 1) t3 = executor.submit(work, 6) # 通过done()方法来判断线程是否完成, True表示已完成、False表示未完成 print(f"t1 done: {t1.done()}") print(f"t2 done: {t2.done()}") print(f"t3 done: {t3.done()}") # 通过result()来获取线程返回的结果, timeout为获取结果的最长等待时间, 若为None则一直等待直到线程结束 # print(f"t1 result: {t1.result(timeout=None)}") # print(f"t2 result: {t2.result(timeout=None)}") # print(f"t3 result: {t3.result(timeout=None)}") # fs:要执行的序列, timeout:等待的最大时间, return_when:wait返回结果的条件; # ALL_COMPLETED等待全部线程执行结束后返回, # FIRST_COMPLETED等待第一个线程结束时返回, # FIRST_EXCEPTION线程一旦产生异常事件就结束 # wait的返回值包含了已完成done和未完成not_done的句柄 # print(f"=== wait:{wait(fs=[t1,t2,t3], timeout=None, return_when=FIRST_COMPLETED)}") # 每完成一个线程响应一个结果,直到work_list中线程全部结束 for future in as_completed([t1, t2, t3]): data = future.result() print(f"as_completed: {data}") # 使用map方法,无需提前使用submit方法;map输出顺序与列表的顺序相同 for result in executor.map(work, [3, 2, 5], timeout=None): print(f"map: {result}")
二、深浅拷贝
浅拷贝只复制指向某个对象的指针而不复制对象本身,新旧对象还是共享同一块内存。
但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象
可变对象:列表、集合、字典(可以进行更改,并且更改后物理地址不会发生改变)
不可变对象:数字、字符串、元组(不可以进行更改,更改后就是一个新的对象了,物理地址发生了变化)
import copy a=['hello',[1,2,3],{'a':1,'b':2},[[1],2]] b=a c=copy.copy(a) print([id(x) for x in a]) print([id(x) for x in b]) a[0]='world' a[1].append(4) a[2]['a']=5 print('a=',a) # a= ['world', [1, 2, 3, 4], {'a': 5, 'b': 2}, [[1], 2]] print('b=',b) # b= ['world', [1, 2, 3, 4], {'a': 5, 'b': 2}, [[1], 2]] print('c=',c) # c= ['hello', [1, 2, 3, 4], {'a': 5, 'b': 2}, [[1], 2]] # 由于a[0]是不可变数据类型,所以a[0]修改了,c[0]仍然指向的是原来的地址
参考来源:https://zhuanlan.zhihu.com/p/25221086
三、属性动态设置
1、hasattr(object, name)
判断一个对象里面是否有name属性或者name方法,返回BOOL值,有name特性返回True, 否则返回False。
2、getattr(object, name[,default])
获取对象object的属性或者方法,如果存在打印出来,如果不存在,打印出默认值,默认值可选。
3、setattr(object, name, values)
给对象的属性赋值,若属性不存在,先创建再赋值。
4、delattr(object, name)
delattr函数用于删除name属性
delattr(x, ‘foobar’)相当于del x.foobar
四、迭代器和生成器
python迭代器有两个基本的方法:iter() 生成迭代器 和 next() 输出迭代器的下一个元素。
生成器yield :调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。调用一个生成器函数,返回的是一个迭代器对象
l = [1, 2, 3, 4] it = iter(l) # 迭代器 print(it.__next__()) print(it.__next__()) print(it.__next__()) print(next(it), "=====分割线=====") def test(): yield 1 print(type(test())) # 只要使用了yield的函数,对象都是迭代器 def fibonacci(n): a, b, count = 0, 1, 0 while True: if (count > n): return yield a # 生成器yield,返回a a, b = b, a + b count += 1 print("运行次数:", count) f = fibonacci(10) # f是一个迭代器,由生成器返回生成 print("迭代器返回值:", next(f)) # 运行到a结束,第一次不会打印count print("--分割线--") print("迭代器返回值:", next(f)) # 再调用一次,从上次运行位置开始。先打印count,再打印迭代器返回值

浙公网安备 33010602011771号