iolist跟list有什么区别?

本文详细解析了Erlang中iolist与list的区别,并通过源码展示iolist的定义和作用,特别强调了iolist在向port发送数据时提高效率的应用场景。
看到erlang-china.org上有个帖子在问这个问题
[quote]一直不太明白iolist,跟list到底有什么区别?请各位大侠指教。。[/quote]

我翻看了半天erlang的文档也没写的太明白,所以就看看源码:
erts/emulator/beam/utils.c


3015int io_list_len(Eterm obj)
3016{
3017 Eterm* objp;
3018 Sint len = 0;
3019 DECLARE_ESTACK(s);
3020 goto L_again;
3021
3022 while (!ESTACK_ISEMPTY(s)) {
3023 obj = ESTACK_POP(s);
3024 L_again:
3025 if (is_list(obj)) {
3026 L_iter_list:
3027 objp = list_val(obj);
3028 /* Head */
3029 obj = CAR(objp);
3030 if (is_byte(obj)) {
3031 len++;
3032 } else if (is_binary(obj) && binary_bitsize(obj) == 0) {
3033 len += binary_size(obj);
3034 } else if (is_list(obj)) {
3035 ESTACK_PUSH(s, CDR(objp));
3036 goto L_iter_list; /* on head */
3037 } else if (is_not_nil(obj)) {
3038 goto L_type_error;
3039 }
3040 /* Tail */
3041 obj = CDR(objp);
3042 if (is_list(obj))
3043 goto L_iter_list; /* on tail */
3044 else if (is_binary(obj) && binary_bitsize(obj) == 0) {
3045 len += binary_size(obj);
3046 } else if (is_not_nil(obj)) {
3047 goto L_type_error;
3048 }
3049 } else if (is_binary(obj) && binary_bitsize(obj) == 0) { /* Tail was binary */
3050 len += binary_size(obj);
3051 } else if (is_not_nil(obj)) {
3052 goto L_type_error;
3053 }
3054 }
3055
3056 DESTROY_ESTACK(s);
3057 return len;
3058
3059 L_type_error:
3060 DESTROY_ESTACK(s);
3061 return -1;
3062}


从源码可以看出来iolist是这样的定义的:
1. []
2. binary
3. 列表, 每个元素是int(0-255)或者binary或者iolist.
其中binary是指 bitsize % 8 == 0 .
int 是0-255


root@ubuntu:/usr/src/otp# erl
Erlang R13B04 (erts-5.7.5) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.5 (abort with ^G)
2> iolist_size(<<>>).
0
3> iolist_size(<<1:1>>).
** exception error: bad argument
in function iolist_size/1
called as iolist_size(<<1:1>>)
4> iolist_size(<<1:8>>).
1
5> iolist_size([]).
0
6> iolist_size(<<1,2>>).
2
7> iolist_size([1,2]).
2
8> iolist_size([1,2, <<1,2>>]).
4
9> iolist_size([1,2, <<1,2>>, [2]]).
5
10> iolist_size([1,2, <<1,2>>, [2]]).
5
11> iolist_size([<<1:1>>]).
** exception error: bad argument
in function iolist_size/1
called as iolist_size([<<1:1>>])
12>


Iolist的作用是用于往port送数据的时候.由于底层的系统调用如writev支持向量写, 就避免了无谓的iolist_to_binary这样的扁平话操作, 避免了内存拷贝,极大的提高了效率.
建议多用.
package com.priusis.report.controller; import com.priusis.api.domain.monitor.TrainIo; import com.priusis.api.domain.monitor.TrainIu; import com.priusis.api.domain.monitor.TrainNet; import com.priusis.core.common.lib.Result; import com.priusis.report.service.IDoorStatusService; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import javax.validation.constraints.NotNull; import java.util.Date; import java.util.List; import java.util.Map; /** * @author yangli * @since 2021/07/01 */ @Validated @RestController @RequestMapping(value = "door_status") public class DoorStatusController { @Resource private IDoorStatusService doorStatusService; // @GetMapping(value = "io/list") public Result<List<TrainIo>> ioList( @RequestParam @NotNull Integer trainNo, @RequestParam @NotNull Integer carriageNo, @RequestParam @NotNull Integer doorNo, @RequestParam(value = "hour") @NotNull @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm") Date minute) { return Result.success(doorStatusService.ioList(trainNo, carriageNo, doorNo, minute)); } @GetMapping(value = "net/list") public Result<List<TrainNet>> netList( @RequestParam @NotNull Integer trainNo, @RequestParam @NotNull Integer carriageNo, @RequestParam @NotNull Integer doorNo, @RequestParam(value = "hour") @NotNull @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm") Date minute) { return Result.success(doorStatusService.netList(trainNo, carriageNo, doorNo, minute)); } 帮我解释一下
03-11
import sys from PyQt5.QtWidgets import QMainWindow, QApplication, QMessageBox from UIpy import Ui_MainWindow # 这里要看你生成的py文件中类名叫什么 from serial.tools import list_ports import pyvisa import configparser from 数据处理 import dataprocess from CreateTMSData import CreateInfoTXT import csv from 自定义线程 import * from queue import Queue import matplotlib.pyplot as plt queue=Queue() #进程数据传输 class Myapp(QMainWindow, Ui_MainWindow): def __init__(self): super().__init__() self.setupUi(self) self.Chip_para = CF.ChipParameter() self.PNA=None self.DC=None self.MCU=None self.config_Path=self.Chip_para.config_Path self.TestN_FilePath=r'Savedata\TestName.cf' self.MCUBusy=False #单片机繁忙标志位 self.PNABusy=False #矢网繁忙标志位 self.running=False #测试进行中标志位 self.countretest=0 #复测计数 self.ThreadArray=[] if os.path.exists(self.config_Path): conf = configparser.ConfigParser() conf.read(self.config_Path, encoding='utf-8') self.comboBox_PNA.addItem(conf.get('仪器地址','PNA_adr')) self.comboBox_DC.addItem(conf.get('仪器地址','DC_adr')) self.comboBox_COM.addItem(conf.get('仪器地址','com')) N=self.readTestN() self.text_Num.setText(str(N)) CreateInfoTXT(self.Chip_para) ######################定义机台测试线程################# self.MultiTestThread=MutliTestThread(self.Chip_para, waittingsotflg=True, queue=queue) self.MultiTestThread.signal.connect(self.callback_finishmultitest) #绑定回传信号事件 #####################sockt测试线程################### self.SocketTestThread=MutliTestThread(self.Chip_para, waittingsotflg=False, queue=queue) self.SocketTestThread.signal.connect(self.finish_runBTN) #重测进程 self.SocketReTestThread = MutliTestThread(self.Chip_para, waittingsotflg=False, rerun=True, queue=queue) self.SocketReTestThread.signal.connect(self.finish_rerunBTN) def Threadplot(self): plt.close('all') # 清除所有图片 for _ in self.Chip_para.TR_Array: fig = queue.get() fig.tight_layout() fig.show() def Event_refreshBTN(self): comlist=list_ports.comports() self.comboBox_COM.clear() if len(comlist)>0: for i in comlist: self.comboBox_COM.addItem(i.name) rm = pyvisa.ResourceManager() port = rm.list_resources() self.comboBox_PNA.clear() self.comboBox_DC.clear() if len(port)>0: for i in port: self.comboBox_PNA.addItem(i) self.comboBox_DC.addItem(i) def Event_startconnect(self): if (not self.PNABusy and not self.MCUBusy): self.PNABusy=True self.MCUBusy=True #####################连接仪器进程##################### connectThread = ConnectBTNThread(self.config_Path) connectThread.signal.connect(self.finishconnect) connectThread.finished.connect(self.on_thread_finished) self.ThreadArray.append(connectThread) connectThread.start() else: self.MessageBoxWarning('单片机或矢网繁忙') def finishconnect(self,IOlist): if self.MCU!=None: #关闭之前的com口 self.MCU.close() self.PNA=IOlist[0] self.DC=IOlist[1] self.MCU=IOlist[2] self.MCUrelease() self.PNArelease() def Event_configBTN_StartProcess(self): if self.PNABusy: self.MessageBoxWarning('矢网繁忙') elif self.PNA==None: self.MessageBoxWarning('仪器未连接') else: self.PNABusy=True Thread=configBNTthreading(self.PNA,self.DC,self.Chip_para) Thread.signal.connect(self.PNArelease) Thread.finished.connect(self.on_thread_finished) self.ThreadArray.append(Thread) Thread.start() def readTestN(self): Path, _ = os.path.split(self.TestN_FilePath) if (not os.path.exists(Path)): os.mkdir(Path) if (os.path.exists(self.TestN_FilePath)): with open(self.TestN_FilePath, 'r') as f: N = int(f.read()) if N < 0: N = 0 else: N = 0 return N def Event_runBTN(self): if self.running: self.MessageBoxWarning('测试运行中') elif self.MCUBusy or self.PNABusy: self.MessageBoxWarning('仪器繁忙') elif self.MCU==None: self.MessageBoxWarning('仪器未连接') else: self.MCUBusy=True self.PNABusy=True self.running=True self.InputNumLock() if(not os.path.exists(self.TestN_FilePath)): N=0 self.text_Num.setText(str(N)) N=int(self.text_Num.toPlainText())+1 if N<1: N=1 # runtest(int(N),self.Chip_para,self.PNA,self.DC,self.MCU) self.SocketTestThread.setIO(self.MCU, self.PNA, self.DC) self.SocketTestThread.settestNum(N) self.SocketTestThread.start() def finish_runBTN(self,test_result,chip_result): N=int(self.text_Num.toPlainText()) if test_result: #测试成功,数据记录加一 self.text_Num.setText(str(N+1)) self.SocketTestThread.join()#等待测试完成 self.Threadplot() #画图 else: pass self.releaseAllIO() def finish_rerunBTN(self,test_result,chip_result): if test_result: self.SocketReTestThread.join() # 等待测试完成 self.Threadplot() #画图 else: pass self.releaseAllIO() def Event_rerunBTN(self): if self.running: self.MessageBoxWarning('测试运行中') elif self.MCUBusy or self.PNABusy: self.MessageBoxWarning('仪器繁忙') elif self.MCU == None: self.MessageBoxWarning('仪器未连接') else: self.MCUBusy = True self.PNABusy = True self.running = True self.InputNumLock() if (not os.path.exists(self.TestN_FilePath)): print('没有已经测试的芯片,无法复测') else: N = int(self.text_Num.toPlainText()) if N<1: N=1 # runtest(int(N),self.Chip_para,self.PNA,self.DC,self.MCU,rerun=True) self.SocketReTestThread.setIO(self.MCU, self.PNA, self.DC) self.SocketReTestThread.settestNum(N) self.SocketReTestThread.start() def getpath(self): ChipName = self.text_ChipName.toPlainText() ChipNum = self.text_ChipNum.toPlainText() if ':' in ChipNum: ChipNum_array = ChipNum.split(':') start = int(ChipNum_array[0]) stop = int(ChipNum_array[1]) save_path_arrary = [ChipName % i for i in range(start, stop + 1)] else: save_path_arrary = [ChipName % int(ChipNum)] return save_path_arrary def Event_display(self): save_path_arrary = self.getpath() for i,TR in enumerate(self.Chip_para.TR_Array): dataprocess(save_path_arrary,SaveAllGain=True,TR=TR,queue=queue) self.Threadplot() def Event_H_init_StartProcess(self): if self.MCUBusy: self.MessageBoxWarning('单片机繁忙') elif self.MCU==None: self.MessageBoxWarning('仪器未连接') else: self.MCUBusy=True arg=[self.Chip_para.PSFile,self.Chip_para.SwitchFile,self.Chip_para.SwitchCHFile, self.Chip_para.SPItype,self.Chip_para.SwitchNum,self.Chip_para.SwitchCHline] ######################配置单片机的线程################### MCUThreading = ConfigMCUThreading(self.MCU,*arg) MCUThreading.signal.connect(self.MCUrelease) MCUThreading.finished.connect(self.on_thread_finished) self.ThreadArray.append(MCUThreading) MCUThreading.start() def Event_startmultitest_StartProcess(self): #开始机台测试按钮事件 if self.running: self.MessageBoxWarning('测试运行中') elif self.PNA == None or self.MCU == None or self.DC == None: self.MessageBoxWarning('仪器未连接') elif (not self.PNABusy) and (not self.MCUBusy): self.MCUBusy = True self.PNABusy = True self.running = True #测试标志位拉高 self.InputNumLock() N=int(self.text_Num.toPlainText()) self.MultiTestThread.setIO(self.MCU,self.PNA,self.DC,self.Chip_para.sottimeout) #机台测试传入IO句柄 self.MultiTestThread.settestNum(N+1) self.MultiTestThread.start() #开始测试线程 else: self.MessageBoxWarning('单片机或矢网繁忙') def callback_finishmultitest(self, test_result, Chip_result): #机台测试回传函数事件 remainnum = int(self.text_Num_2.toPlainText()) #读取剩余次数 N = int(self.text_Num.toPlainText()) #读取已经测试芯片 if test_result: print('测试完成') N = N + 1 if Chip_result: testtext = '开始下次测试' self.sendcommand('OK') self.countretest=0 elif self.countretest >=self.Chip_para.retestNum: testtext = '开始下次测试' self.sendcommand('NG') self.countretest=0 else: testtext='开始重测' self.sendcommand('retest') self.countretest=self.countretest+1 if remainnum>=0: remainnum=remainnum+1 N = N - 1 if remainnum >= 1: remainnum = remainnum - 1 self.text_Num_2.setText(str(remainnum)) # 更新剩余测试次数 self.text_Num.setText(str(N)) # 更新已测试芯片数 self.MultiTestThread.join() #等待测试完成 self.Threadplot() # 画图 if self.running and remainnum!=0: print(testtext) self.MultiTestThread.settestNum(N+1) self.MultiTestThread.start() # 开始下次测试 else: print('结束测试') self.releaseAllIO() else: print('结束测试') self.releaseAllIO() def releaseAllIO(self,*args): self.running = False self.MCUrelease() self.PNArelease() self.InputNumUnLock() def Event_finishmultitest(self): #此次测试结束后停止测试 按钮事件 if self.MultiTestThread.isRunning(): print('收到停止命令,此次测试结束后,将停止测试') self.running=False #测试标志拉低 下次测试结束 def MCUrelease(self): self.MCUBusy=False def PNArelease(self): self.PNABusy=False def MessageBoxWarning(self,message): QMessageBox.warning(self, '警告', message) def Event_FiltChip(self): TMSDATApath=r'SaveData\_TMSData' ChipOKpath=os.path.join(TMSDATApath,'ChipOK') ChipNGpath=os.path.join(TMSDATApath,'ChipNG') if (not os.path.exists(ChipOKpath)): os.mkdir(ChipOKpath) if (not os.path.exists(ChipNGpath)): os.mkdir(ChipNGpath) fileList = os.listdir(TMSDATApath) # 遍历一层 iok=0 iNG=0 for f in fileList: f_path = os.path.join(TMSDATApath, f) # 如果是文件 f_array=f.split('.') if os.path.isfile(f_path) and f_array[1] == 'csv': ChipNum=int(f_array[0].replace('Chip','')) with open(f_path,'r') as f: read=list(csv.reader(f)) #回读芯片数据 if read[-1][0] =='1': #判读为OK iok = iok + 1 read[-1][1]=ChipNum writepathfile=os.path.join(ChipOKpath,'%d.csv'%iok) elif read[-1][0] =='2': #判读为NG iNG = iNG + 1 read[-1][1]= ChipNum writepathfile = os.path.join(ChipNGpath, '%d.csv' % iNG) with open(writepathfile,'w',newline='') as f: CSVwriter=csv.writer(f) CSVwriter.writerows(read) print('分类完成') def sendcommand(self,command): if command == 'OK': write_UART(self.MCU,'23f01123',num=1) if command == 'NG': write_UART(self.MCU,'23f01223',num=1) if command == 'retest': write_UART(self.MCU,'23f01323',num=1) def InputNumLock(self): self.text_Num.setEnabled(False) self.text_Num_2.setEnabled(False) def InputNumUnLock(self): self.text_Num.setEnabled(True) self.text_Num_2.setEnabled(True) def on_thread_finished(self): self.ThreadArray=[t for t in self.ThreadArray if t.isRunning()] if __name__ == "__main__": # 解决界面模糊,缩放比例问题 QApplication.setHighDpiScaleFactorRoundingPolicy(Qt.HighDpiScaleFactorRoundingPolicy.PassThrough) # 适应高DPI设备 QApplication.setAttribute(Qt.AA_EnableHighDpiScaling) # 解决图片在不同分辨率显示模糊问题 QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps) app = QApplication(sys.argv) win1 = Myapp() win1.show() sys.exit(app.exec_())
最新发布
12-05
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值