Generators (usable with async)

Description

Based on the concept described in the previous article (contextual async), I have added the support of generators.

It has 2 main advantages:

  • You can add generators to existing code just by yielding, you do not have the implementaztion of all the callers (of course, it will be “caught” by a caller)
  • You can have asynchronous generators. This means that while you generate, you can have other tasks running in parallel with the generator

Examples

The examples can be found in the github 5a5 project (https://github.com/chbailly/5a5/)

Again, this is a prototype but it is possible to do lot’s of things already…

example3

A very simple generator, as you can see f2 does not have specific code (no yield from).

#include "pch.h"
#include <iostream>
#include "async.h"


int gen_double(int k) {
	std::cout << "send " << k*2 << std::endl;
	yield<int>(k*2);
	return 1;
}


int f2() {
	int k = 1;
	while (1) {
		std::cout << "send " << k << std::endl;
		yield<int>(k);
		gen_double(k++);
	}
}

int f1() {
	return f2();
}


int main()
{
	generator<int> gen(f1);
	int k;

	for (int i = 0; i < 10; i++) {
		k = gen.next();
		std::cout << "receive: " << k << std::endl;
	}
	std::cout << "end" << std::endl;
}

Output:

send 1
receive: 1
send 2
receive: 2
send 2
receive: 2
send 4
receive: 4
send 3
receive: 3
send 6
receive: 6
send 4
receive: 4
send 8
receive: 8
send 5
receive: 5
send 10
receive: 10
end

The output corresponds to what is expected from a generator

Example 4

In this more complex example, we have a generator which yields numbers requested to a server.

Because we have async code in this generator (the wait_socket_rcv), we can run a task in the background. In the following example this is a clock.

#include "pch.h"
#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <time.h>
#include <string>
#include "async.h"

#define DEFAULT_PORT "27015"

extern SOCKET do_connect();

int call_server(int input) {
	int recvbuflen = 10;
	char *sendbuf = new char[recvbuflen];
	char *recvbuf = new char[recvbuflen];

	strcpy_s(sendbuf, recvbuflen, std::to_string(input).c_str());

	int iResult;
	SOCKET ConnectSocket = do_connect();
	// Receive until the peer closes the connection


	iResult = send(ConnectSocket, sendbuf, recvbuflen, 0);
	wait_socket_rcv(ConnectSocket);
	iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);

	closesocket(ConnectSocket);
	WSACleanup();
	return atoi(recvbuf);
}


int calc() {
	int k = 4;
	while (1) {
		yield<int>(call_server(k));
		k++;
	}
	return 1;
}

int clock1s() {
	int count = 0;
	while (1) {
		wait_duration(1);
		std::cerr << "count: " << count++ << std::endl;
	}
	return 0;
}



int main()
{
	time_t start, endt; // we will display the total time.
	time(&start);

	future<int> fut_clock(clock1s);
	fut_clock.run();

	generator<int> gen_calc(
		[]() { return calc(); });

	
	for (int k = 0; k < 4; k++) {
		std::cout << "Recv: " << gen_calc.next() << "----------" << std::endl;;
	}


	std::cout << "End " << std::endl;;

	time(&endt);
	std::cout << "It took: " << difftime(endt, start) << std::endl;
	int a;
	std::cin >> a;

}

The output is :

count: 0
count: 1
count: 2
count: 3
Recv: 4----------
count: 4
count: 5
count: 6
count: 7
count: 8
Recv: 5----------
count: 9
count: 10
count: 11
count: 12
count: 13
count: 14
Recv: 6----------
count: 15
count: 16
count: 17
count: 18
count: 19
count: 20
count: 21
Recv: 7----------
End
It took: 22

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s