반응형

Dart 의 비동기/동기(async/ sync programming) 표현 방법은 상당히 직관적이면서도 편리한 부분들이 많습니다.

효율적인 동작을 위한 코딩을 하려다 보면 필연적으로 async로 코드 작성이 필요로 하게 되죠.

 

아래 간단한 주제를 가지고 한번 얘기 해보고자 합니다.

 

A라는 데이타 목록을 가지고 B라는 과정을 거쳐서 C라는 결과를 도출하고 D라는 데이타 목록으로 저장을 하려고 합니다.
1. A의 각 항목들은 B라는 과정을 거칠때 1~2 초 정도 시간이 걸린다. 
2. B 과정을 입력 A 데이타에 따라 처리 시간이 달라진다.(1초 또는 2초)
3. D에 저장 되는 순서는 A의 순서와 같아야 한다.

일단 A항목들을 순차적으로 처리하게 되면, A의 개수만큼 시간이 늘어나게 됩니다.

따라서 비동기(async)프로그래밍를 고려하게 될 것입니다.

 

위의 상황에 대해서 코딩을 해보면,  가장먼저 다음과 같이 생각해볼 수 있을 것입니다.

A = srcData, B =Future.delayed() , C =  A와 같은 type , D = dstData 라고 합시다.

import 'dart:async';
import 'dart:math';


List<String> srcData=[];
List<String> dstData=[];

init(){
  for( int i = 0;i<24; i++ ){
    srcData.add('mmm_${i}');
  }
}

Future copyToDst(int i){// test를 위해서 1~2초의 랜덤 수행 순서로, src에서 dstData 에 copy 하는 내용.
  return Future.delayed(Duration(seconds: Random().nextInt(2)),(){
    dstData.add(srcData[i]);
    print('src[$i]=>dst');
  });
}



fillDest() async{
  init();
  print("fillDest: length=${srcData.length}");
  for(int s = 0; s<srcData.length ;s++){
    copyToDst(s);
  }
}

void main() async{
 await fillDest();
 await Future.delayed(Duration(seconds: 5));
 print(dstData);
  
}

1초 또는 2초에 처리가 완료 되면, dstData에 저장을 하게 됩니다.

실행 결과는 아래와 같습니다.

기본적인 동작은 하는것 처럼 보입니다.

 

<실행 결과>

fillDest: length=24
src[3]=>dst
src[4]=>dst
src[5]=>dst
src[8]=>dst
src[10]=>dst
src[11]=>dst
src[15]=>dst
src[16]=>dst
src[20]=>dst
src[21]=>dst
src[22]=>dst
src[0]=>dst
src[1]=>dst
src[2]=>dst
src[6]=>dst
src[7]=>dst
src[9]=>dst
src[12]=>dst
src[13]=>dst
src[14]=>dst
src[17]=>dst
src[18]=>dst
src[19]=>dst
src[23]=>dst
[mmm_3, mmm_4, mmm_5, mmm_8, mmm_10, mmm_11, mmm_15, mmm_16, mmm_20, mmm_21, mmm_22, mmm_0, mmm_1, mmm_2, mmm_6, mmm_7, mmm_9, mmm_12, mmm_13, mmm_14, mmm_17, mmm_18, mmm_19, mmm_23]

 

음... 그런데  결과에서 보듯이 "mmm_숫자" 결과의 순서가 srcData의 순서와 맞지 않는 것을 볼수 있습니다.

 

이제 여기서 몇가지 고민을 하게 되겠죠? 가령 "어떻게 순서를 맞출 것인가? " 와 같은 것 말이죠.

대략 한 3가지 방법을 생각해 볼 수 있을것 같네요..

 

첫번째,  copyToDest를  await 으로 처리하는 방법입니다.

  for(int s = 0; s<srcData.length ;s++){
    await copyToDst(s);
  }

 직접 실행해보면, .. 으악... 이런 최악의 수네요..ㅠ_ㅠ 실행시간이 너무 오래걸려요.

 

 

두번째,  map을 이용하는 방법이 있겠네요. 

map을 이용해서 srcData의 순서를 map의  index로 사용하는 방법이죠.

import 'dart:async';
import 'dart:math';


List<String> srcData=[];
Map<int, String> dstData={};

init(){
  for( int i = 0;i<24; i++ ){
    srcData.add('mmm_${i}');
  }
}

Future copyToDst(int i){// test를 위해서 1~2초의 랜덤 수행 순서로, src에서 dstData 에 copy 하는 내용.
  return Future.delayed(Duration(seconds: Random().nextInt(2)),(){
    dstData[i] = srcData[i];
    print('src[$i]=>dst');
  });
}



fillDest() async{
  init();
  print("fillDest: length=${srcData.length}");
  for(int s = 0; s<srcData.length ;s++){
     copyToDst(s);
  }
}

void main() async{
 await fillDest();
 await Future.delayed(Duration(seconds: 5));
 print(dstData);
  
}

 

<실행결과>

fillDest: length=24
src[0]=>dst
src[1]=>dst
src[2]=>dst
src[3]=>dst
src[5]=>dst
src[6]=>dst
src[7]=>dst
src[11]=>dst
src[12]=>dst
src[16]=>dst
src[18]=>dst
src[21]=>dst
src[22]=>dst
src[4]=>dst
src[8]=>dst
src[9]=>dst
src[10]=>dst
src[13]=>dst
src[14]=>dst
src[15]=>dst
src[17]=>dst
src[19]=>dst
src[20]=>dst
src[23]=>dst
{0: mmm_0, 1: mmm_1, 2: mmm_2, 3: mmm_3, 5: mmm_5, 6: mmm_6, 7: mmm_7, 11: mmm_11, 12: mmm_12, 16: mmm_16, 18: mmm_18, 21: mmm_21, 22: mmm_22, 4: mmm_4, 8: mmm_8, 9: mmm_9, 10: mmm_10, 13: mmm_13, 14: mmm_14, 15: mmm_15, 17: mmm_17, 19: mmm_19, 20: mmm_20, 23: mmm_23}

실행결과를 보시면 데이타의 순서는 처리속도에 따라 순서가 달라졌지만, 우리는 map의 index를 사용할 수 있기 때문에 index 순서로 결과를 뽑아볼수 있습니다. ^^ 매우 좋은 결과네요. 

속도도 거의 차이가 없고, 결과도 좋고요.

한가지 걸리는 것은 , dstData를 얻기까지 1~2초가 걸리는데, data가 정상적으로 들어왔는지, 언제 사용해야 하는지가 약간은 애매하네요.

 

 

 

세번째, dstData를 Future List로 변경하는 방법인데요. 

dstData 의 형태를 List<String> 에서 List<Future<String>> 변경하고 copyToDst의 형태도 dstData에 Future<String>을 추가하도록 변경되었습니다.

이렇게 하면 dstData 에는 실행 결과가 들어가는 것이 아니라 실행 명령 순서인 Future<String> 을 저장하는 것을 의도 합니다.

import 'dart:async';
import 'dart:math';


List<String> srcData=[];
List<Future<String>> dstData=[];

init(){
  for( int i = 0;i<24; i++ ){
    srcData.add('mmm_${i}');
  }
}


Future copyToDst2(int i)async{// test를 위해서 1~2초의 랜덤 수행 순서로, src에서 dstData 에 copy 하는 내용.
  return dstData.add(Future<String>.delayed(Duration(seconds: Random().nextInt(2)),(){
    print('src[$i]=>dst');
    return srcData[i];
  }));
}


fillDest() async{
  init();
  print("fillDest: length=${srcData.length}");
  for(int s = 0; s<srcData.length ;s++){
    copyToDst2(s);
  }
}

void main() async{
 await fillDest();
 await Future.delayed(Duration(seconds: 5));
  
  
 List<String> l=[];
 for (var d in dstData){
   l.add(await d);
 }
  
  
 print(l);
  
}

 

추후 Future<String>의 결과를 얻기 위해서는 await dstData[i] 형태로 사용하면 String을 얻어올 수 있게 됩니다.

 

<실행 결과>

fillDest: length=24
src[0]=>dst
src[1]=>dst
src[2]=>dst
src[3]=>dst
src[5]=>dst
src[6]=>dst
src[7]=>dst
src[10]=>dst
src[11]=>dst
src[12]=>dst
src[16]=>dst
src[20]=>dst
src[23]=>dst
src[4]=>dst
src[8]=>dst
src[9]=>dst
src[13]=>dst
src[14]=>dst
src[15]=>dst
src[17]=>dst
src[18]=>dst
src[19]=>dst
src[21]=>dst
src[22]=>dst
[mmm_0, mmm_1, mmm_2, mmm_3, mmm_4, mmm_5, mmm_6, mmm_7, mmm_8, mmm_9, mmm_10, mmm_11, mmm_12, mmm_13, mmm_14, mmm_15, mmm_16, mmm_17, mmm_18, mmm_19, mmm_20, mmm_21, mmm_22, mmm_23]

 

 

추가로, 

map을 사용했을때 " dstData 언제 사용해야 하는지가 약간은 애매하네요." 라고 했던 부분에 대해서 추가로 생각해보자면,

List<Future<String>> 을 사용했던것 처럼, map<int , Future<String>> 으로 사용하게 되면, 필요한 데이타를 사용할때 await을 활용하여 data 결과가 채워지기를 기다릴 수 있겠는데요 ? 

 

아무튼 async 프로그래밍을 다루기에 편리한 언어인 dart 인데 이를 활용 안할 이유가 없을것 같죠? 그렇죠?

 

다들 dart의  async, async* sync, sync* 에 대해서 찾아보시고 알아두시면 즐거운 코딩 생활에 도움이 될것 같습니다.

 

 

반응형

 

byte[] to String

 byte[] ={'a','b',};
 String str = new String(data, StandardCharsets.UTF_8);
 
 
 
 byte[] ={'a','b',};
 String str = new String(data);

 

String.toCharArray()

 

String str = "abcdefg";
char [] array = str.toCharArray();

 

 

String.getBytes();

String str= "Hello";
byte buff[] = str.getBytes();
//charset
byte buff1[] = str.getBytes(StandardCharsets.UTF_8);

//charset string
try {
	byte buff2[] = str.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
	e.printStackTrace();
}

 

byte[] to String

String str = "Hello";
byte buff[] = str.getBytes();
String str1 = new String(buff);

 

 

InputStream -> ByteArrayOutputStream -> String

(주로 File IO, Asset , network등 이용하는 경우 많이 사용하게 됨.)

 

InputStream input = this.getContext().getAssets().open("mytextfile.txt");

try {
	ByteArrayOutputStream result = new ByteArrayOutputStream();

	byte buff[] = new byte[1024];
	int length;
	while( (length = input.read(buff,0, 1024)) != -1){
		result.write(buff,0,length);
	}
	String str = result.toString("UTF-8");

} catch (IOException e) {
	e.printStackTrace();
}

 

 

 

'Android, Java,Kotlin' 카테고리의 다른 글

JNI, Native code build 시 유의점  (0) 2022.04.21
[Copy&Paste] Array를 List로 바꾸기  (0) 2020.11.04
[Android] JavaDoc 사용법 링크.  (0) 2020.10.28
반응형


일반적인 String compare 함수는 정확한 string을 비교해서 처리해야 하는 경우들이 많습니다.


그런데 간혹, 문자열이 엇비슷하면 같다고 처리하고 싶을 때도 있습니다.


예를 들면,  

1. "나 ^^ 이뽀 :)~" 와 "나 ^^;;; 이뽀~~~???" 이런 문자열들을 같은 취급 하고 싶은 경우, 

2. "이 름" 과 "이름" 과 같이 공백을 무시하고 싶은경우,


3. 마지막으로  "오늘 아침 날씨" 와 "오늘 오전 날씨" 와 같이 의미 갖는 단어들을  같은 것으로  취급하고 싶은 경우,


들 일것입니다.


3번은 단순 코드로는 해결하기 힘든 내용일 것입니다. 

'비슷한 문자열'이라는 개념을 정리하는 차원에서 써 놓은 항목입니다.



일단 순수한 코드차원에서 접근하자면, 1,2번의 경우에 대해서는 간단한 해결책이 있습니다.


특수문자나 공백을 제외하고 문자열을 비교하는 코드를 작성하여 이를 사용하면 됩니다.





#include <string>

using namespace std;



bool inline
is_ignorable_ch(unsigned char c)
{
if (c<= 0x2F) return true; // control code
/*
U+0020      20  SPACE
U+0021  !   21  EXCLAMATION MARK
U+0022  "   22  QUOTATION MARK
U+0023  #   23  NUMBER SIGN
U+0024  $   24  DOLLAR SIGN
U+0025  %   25  PERCENT SIGN
U+0026  &   26  AMPERSAND
U+0027  '   27  APOSTROPHE
U+0028  (   28  LEFT PARENTHESIS
U+0029  )   29  RIGHT PARENTHESIS
U+002A  *   2a  ASTERISK
U+002B  +   2b  PLUS SIGN
U+002C  ,   2c  COMMA
U+002D  -   2d  HYPHEN-MINUS
U+002E  .   2e  FULL STOP
U+002F  /   2f  SOLIDUS
*/  
else if(0x3A <= c && c<= 0x40) return true;
/*  
U+003A : 3a  COLON
U+003B  ;   3b  SEMICOLON
U+003C  <   3c  LESS-THAN SIGN
U+003D  =   3d  EQUALS SIGN
U+003E  >   3e  GREATER-THAN SIGN
U+003F  ?   3f  QUESTION MARK
U+0040  @   40  COMMERCIAL AT
*/

else if(0x5B <= c && c<= 0x60) return true;
/*
U+005B  [   5b  LEFT SQUARE BRACKET
U+005C  \   5c  REVERSE SOLIDUS
U+005D  ]   5d  RIGHT SQUARE BRACKET
U+005E  ^   5e  CIRCUMFLEX ACCENT
U+005F  _   5f  LOW LINE
U+0060  `   60  GRAVE ACCENT
*/
else if(0x7B <= c && c<= 0x7E) return true;
/*
U+007B  {   7b  LEFT CURLY BRACKET
U+007C  |   7c  VERTICAL LINE
U+007D  }   7d  RIGHT CURLY BRACKET
U+007E  ~   7e  TILDE
*/
return false;
}

bool
is_similar(const std::string& str1, const std::string& str2)
{
const char* s1 = str1.c_str();
const char* s2 = str2.c_str();
int l1 = str1.size();
int l2 = str2.size();

int i=0,j=0;
for( ;i<l1 && j<l2;)
{
if(is_ignorable_ch(s1[i])){i++; continue;}
if(is_ignorable_ch(s2[j])){j++; continue;}
if(s1[i] != s2[j]) return false;
i++;
j++;
}

for(i ;i<l1;i++)
if(!is_ignorable_ch(s1[i])) return false;

for(j ;j<l2;j++)
if(!is_ignorable_ch(s2[j])) return false;

return true;
}


#define TEST(P1, P2, _EXPECT) do{\
int r = is_similar(P1, P2);\
printf( "%s\t r= %s:\t %s, %s\n"\
,(r == (_EXPECT))?"PASS":"FALSE" \
,(r==true)?"true":"false"\
,#P1 \
,#P2);\
}while(0)

void compare_test()
{

int no = 0;
TEST("","", true);

TEST("", "aaa", false);


TEST("차차차... 해", "", false);

TEST("안녕하세요. ", " 안 녕 하세요, ",true);
TEST("hello... 나는 누구 ?", "hello나는누구",true);
TEST("hello... ", "he ll. o",true);
}



result 


PASS  r= true:  "", ""

PASS  r= false:  "", "aaa"

PASS  r= false:  "차차차... 해", ""

PASS  r= true:  "안녕하세요. ", " 안 녕 하세요, "

PASS  r= true:  "hello... 나는 누구 ?", "hello나는누구"

PASS  r= true:  "hello... ", "he ll. o"



+ Recent posts