定义main函数的语句
if __name__=='__main__':
一、python多线程编程
1.导入模块:
import threading
2.获取已激活的线程数
threading.active_count()
3.查看所有线程信息
threading.enumerate()
# [<_MainThread(MainThread, started 140736011932608)>, <Thread(SockThread, started daemon 123145376751616)>]
4.查看现在正在运行的线程
threading.current_thread()
# <_MainThread(MainThread, started 140736011932608)>
5.添加线程
threading.Thread()接收参数target代表这个线程要完成的任务,需自行定义
thread = threading.Thread(target=thread_job,) # 定义线程
thread.start() # 让线程开始工作
6.join功能
Thread.join()
作用为阻塞主线程main,即在子线程未返回的时候,主线程等待其返回然后再继续执行.
若不加入join,则会导致线程任务还未完成便输出all done。如果要遵循顺序,可以在启动线程后对它调用join:
added_thread.start()
added_thread.join()
print("all done\n")
使用join对控制多个线程的执行顺序非常关键。举个例子,假设我们现在再加一个线程T2,T2的任务量较小,会比T1更快完成,则会导致顺序错乱。
所以需要:
thread_1.start()
thread_1.join() # notice the difference!
thread_2.start()
print("all done\n")
具体例子:
为了规避不必要的麻烦,推荐如下这种1221的V型排布:
thread_1.start() # start T1
thread_2.start() # start T2
thread_2.join() # join for T2
thread_1.join() # join for T1
print("all done\n")
"""
T1 start
T2 start
T2 finish
T1 finish
all done
"""
7.储存进程结果队列
使用队列的原因:多线程调用的函数不能用return返回值
导入线程,队列的标准模块
from queue import Queue
q.put(l) #q为一个对队列,将列表l加到队列里。
在多线程函数中定义一个Queue,用来保存返回值,代替return,定义一个多线程列表,初始化一个多维数据列表,用来处理:
def multithreading():
q =Queue() #q中存放返回值,代替return的返回值
threads = []
data = [[1,2,3],[3,4,5],[4,4,4],[5,5,5]]
在多线程函数中定义四个线程,启动线程,将每个线程添加到多线程的列表中
for i in range(4): #定义四个线程
t = threading.Thread(target=job,args=(data[i],q)) #Thread首字母要大写,被调用的job函数没有括号,只是一个索引,参数在后面
t.start()#开始线程
threads.append(t) #把每个线程append到线程列表中
分别join四个线程到主线程
for thread in threads:
thread.join()
定义一个空的列表results,将四个线运行后保存在队列中的结果返回给空列表
results
results = []
for _ in range(4):
results.append(q.get()) #q.get()按顺序从q中拿出一个值
print(results)
注:错误写法:
for thread in threads:
thread.start()
thread.join()
原因:执行join之后,主线程被线程1阻塞,在线程1返回结果之前,主线程无法执行下一轮循环.
正确写法:
for thread in threads:
thread.start()
for thread in threads:
thread.join()
8.解释器被一个全局解释器GIL锁保护着,它确保任何时候都只有一个Python线程执行。 GIL最大的问题就是Python的多线程程序并不能利用多核CPU的优势 。
GIL只会影响到那些严重依赖CPU的程序(比如计算型的)。
如果你的程序大部分只会涉及到I/O,比如网络交互,那么使用多线程就很合适, 因为它们大部分时间都在等待。
9.lock锁
在每个线程执行运算修改共享内存之前,执行lock.acquire()将共享内存上锁, 确保当前线程执行时,内存不会被其他线程访问,
执行运算完毕后,使用lock.release()将锁打开, 保证其他的线程可以使用该共享内存。
主函数中定义一个Lock
if __name__== '__main__':
lock=threading.Lock()
函数一和函数二加锁
def job1():
global A,lock
lock.acquire()
for i in range(10):
A+=1
print('job1',A)
lock.release()
def job2():
global A,lock
lock.acquire()
for i in range(10):
A+=10
print('job2',A)
lock.release()
二、python多进程编程
1.导入线程进程标准模块
import multiprocessing as mp
创建线程和进程
t1 = td.Thread(target=job,args=(1,2))
p1 = mp.Process(target=job,args=(1,2))
分别启动线程和进程
t1.start()
p1.start()
分别连接线程和进程
t1.join()
p1.join()
例子:
if __name__=='__main__':
p1 = mp.Process(target=job,args=(1,2))
p1.start()
p1.join()
三、python窗口编程
1.定义 window 窗口 和 window的一些属性, 然后书写窗口内容, 最后执行
window.mainloop让窗口活起来.
import tkinter as tk
window = tk.Tk()
window.title('my window')
window.geometry('200x100')
这里是窗口的内容
window.mainloop()
2.这次我们会建立一个用来描述的标签 tk.Label,
比如:
l = tk.Label(window,
text='OMG! this is TK!', # 标签的文字
bg='green', # 背景颜色
font=('Arial', 12), # 字体和字体大小
width=15, height=2 # 标签长宽
)
l.pack() # 固定窗口位置
3.引入按钮 tk.Button 的概念, 没点一次按钮, 标签变化一次. 用一下内容替换上面的标签.
把需要变化的文字存成变量 var:
var = tk.StringVar() # 这时文字变量储存器
l = tk.Label(window,
textvariable=var, # 使用 textvariable 替换 text, 因为这个可以变化
bg='green', font=('Arial', 12), width=15, height=2)
l.pack()
接着我们来做 按钮 tk.Button:
b = tk.Button(window,
text='hit me', # 显示在按钮上的文字
width=15, height=2,
command=hit_me) # 点击按钮式执行的命令
b.pack() # 按钮位置
那么点击是的命令我们用 if else 语句来判断. 用 on_hit 来判断当前状态.
on_hit = False # 默认初始状态为 False
def hit_me():
global on_hit
if on_hit == False: # 从 False 状态变成 True 状态
on_hit = True
var.set('you hit me') # 设置标签的文字为 'you hit me'
else: # 从 True 状态变成 False 状态
on_hit = False
var.set('') # 设置 文字为空