Why does not the runOn() method execute map operator on the next available thread from the pool when the current executing threads go to wait state? - project-reactor

I am trying to execute the following code on a 4 core machine. I have 5 threads in the pool and within the map operator, I put the executing thread to sleep for a few seconds.
I expect that the core would put the executing thread on sleep and when the next event is available, should perform the map operation on the next available thread from the thread pool, BUT is not the behavior I see.
I see that the 4 threads from the pool go on wait for 13 seconds and process the next event only after the wait is complete.
Why is the runOn() method not executing the map operator on the next available thread from the pool when the threads go to wait state?
I am using reactor-core version '3.0.7.RELEASE'
CountDownLatch latch = new CountDownLatch(10);
ExecutorService executorService = Executors.newFixedThreadPool(5);
Flux<Integer> flux = Flux.just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
flux.parallel()
.runOn(Schedulers.fromExecutorService(executorService))
.map(l -> {
Logger.log(ReactorParallelTest.class, "map1", "inside run waiting for 13 seconds");
try {
Thread.sleep(13000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Logger.log(ReactorParallelTest.class, "map1", "l=" + l);
latch.countDown();
return l;
}).subscribe(l -> {
Logger.log(ReactorParallelTest.class, "onNext", "l=" + l);
}, error -> System.err.println(error),
() -> {
Logger.log(ReactorParallelTest.class, "onComplete", "inside complete.");
executorService.shutdown();
});
try {
latch.await(60, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}

You are blocking all your rails with this code. 4 rails will be started (number of CPUs), and they will immediately request 1 element each from the source. Since you immediately block in the map when this is done, the rail cannot request more from upstream, so in effect you only get 4 elements at a time, block, get more, block... The parallelism is more limited than the capacity of the thread pool. If you want to put all threads to good use, do .parallel(5) (same configuration as the thread pool).
On a side note, the subscribe(lambda) from ParallelFlux will invoke the onComplete callback for each rail. If you want to merge back to a single sequence (and single complete), use a .sequential() just before .subscribe.

Related

FreeRTOS Mutex Unexpected behaviour

#include "main.h"
#include "FreeRTOS.h"
#include "semphr.h"
#include "task.h"
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
void Task1(void *argument);
void Task2(void *argument);
void PrintMsg(char *data);
/* USER CODE BEGIN PFP */
SemaphoreHandle_t hMutex = NULL;
TaskHandle_t hTask1 = NULL;
TaskHandle_t hTask2 = NULL;
UART_HandleTypeDef huart2;
int main(void) {
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART2_UART_Init();
/* USER CODE BEGIN 2 */
xTaskCreate(Task1, "Task 1", configMINIMAL_STACK_SIZE, NULL, 2, &hTask1);
xTaskCreate(Task2, "Task 2", configMINIMAL_STACK_SIZE, NULL, 2, &hTask2);
/* USER CODE END 2 */
hMutex = xSemaphoreCreateMutex();
if (hMutex == NULL) {
PrintMsg("Mutex not created\r\n");
} else {
PrintMsg("Mutex created\r\n");
}
vTaskStartScheduler();
/* USER CODE BEGIN WHILE */
while (1) {
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
void Task1(void *argument) {
/* USER CODE BEGIN 5 */
/* Infinite loop */
for (;;) {
if (xSemaphoreTake(hMutex,2000) == pdTRUE) {
PrintMsg("Shared Resource Start and Executing Task 1\r\n");
xSemaphoreGive(hMutex);
PrintMsg("Shared Resource End and Executing Task 1\r\n");
vTaskDelay(100);
} else {
PrintMsg("Task 1 Didn't get access to shared resource\r\n");
}
}
/* USER CODE END 5 */
}
void Task2(void *argument) {
/* USER CODE BEGIN 5 */
/* Infinite loop */
for (;;) {
if (xSemaphoreTake(hMutex,2000) == pdTRUE) {
PrintMsg("Shared Resource Start and Executing Task 2\r\n");
//xSemaphoreGive(hMutex);
PrintMsg("Shared Resource End and Executing Task 2\r\n");
vTaskDelay(100);
} else {
PrintMsg("Task 2 Didn't get access to shared resource\r\n");
}
}
/* USER CODE END 5 */
}
void PrintMsg(char *data) {
int i = 0;
while (*(data + i) != '\0') {
HAL_UART_Transmit(&huart2, (uint8_t*) &data[i], 1, 0xFF);
i++;
}
}
HW USED:STM32F446RE
When i run this code,I get output as follows
//Output Start
Mutex created
Shared Resource Start and Executing Task 1
Shared Resource End and Executing Task 1
Task 2 Didn't get access to shared resource
Task 1 DiTask 2 Didn't get access to shared resource
Task 1 Didn't get access to shared resource
Task 2 Didn't get access to shared resource
.
.
//Output End
Question1)
Considering Task1 was scheduled first as the priority of Task1 and 2 are same.
Task1 is executed correctly.
After this,Task2 is scheduled but was not able to take the mutex because of which i got output as "Task 2 Didn't get access to shared resource".Why is this so?
Question2 )
"Task 1 DiTask 2 Didn't get access to shared resource" in this line,it seems that Task1 was exceuting but it got preempted by Task2 which should have not happened as both the Tasks have same priority??
Q1: The likely explanation here is that you're being fooled by competing tasks overwriting each others' buffered UART output. UART is slow, task switching is fast :)
After Task1 prints "Shared Resource Start and Executing Task 1" and releases the mutex for the first time, scheduler immediately switches to Task2 (maybe because Task1 has used up its time slot?). Task2 grabs the mutex, quickly spits both of its messages into UART buffer and enters sleep for 100 ticks. The scheduler immediately switches back to Task1, but unfortunately the buffered messages from Task2 haven't hit the UART output yet. UART buffer gets overwritten by the message "Shared Resource End and Executing Task 1" before a single byte of Task2-s messages is printed.
After that the entire process stalls because you haven't released the mutex in Task2.
Q2: tasks with equal priorities get preempted by each other when the scheduler decides so (usually when they enter sleep or have exhausted their time slot)
I would recommend this tutorial/book, chapter 3 for a great explanation of how tasks work.
USART is a resource, so it can't be shared by two tasks without a sync mechanism, like a mutex. Your usage of PrintMsg() violates this rule.
The scheduler is run at configTICK_RATE_HZ frequency. If configUSE_TIME_SLICING is 1 (or undefined), the scheduler switches between equal priority tasks. If you don't want this default behavior, set configUSE_TIME_SLICING to 0.
Keep it in mind that your configTICK_RATE_HZ setting of 1000 gives at most ~1 ms runtime to each task, unless there are no other tasks ready to run. Higher priority tasks can also preempt it before that 1 ms passes. With 115200 baud rate, you can send ~10 bytes or so in this ~1 ms time period.

How to run parallel processes in Contiki

I want to create two processes that should be executed parallelly. I am trying with following code:
PROCESS(hello_world_process, "Hello world process");
PROCESS(hello_world_process2, "Hello world process2");
AUTOSTART_PROCESSES(&hello_world_process,&hello_world_process2);
/*---------------------------------------------------------------------------*/
int i;
void program1(void)
{
for (i=0;i<10;i++)
{
printf("%d from 1st process\n",i);
}
}
void program2(void)
{
for (i=0;i<10;i++)
{
printf("%d from IIund process\n",i);
}
}
PROCESS_THREAD(hello_world_process, ev, data)
{
PROCESS_BEGIN();
program1();
PROCESS_END();
}
PROCESS_THREAD(hello_world_process2, ev, data)
{
PROCESS_BEGIN();
program2();
PROCESS_END();
}
But the second process is getting started after the completion of the first process.
Output:
Contiki-list-1532-g2ca33d4 started with IPV6, RPL
Rime started with address 1.2.3.4.5.6.7.8
MAC nullmac RDC nullrdc NETWORK sicslowpan
Tentative link-local IPv6 address fe80:0000:0000:0000:0302:0304:0506:0708
0 from 1st process
1 from 1st process
2 from 1st process
3 from 1st process
4 from 1st process
5 from 1st process
6 from 1st process
7 from 1st process
8 from 1st process
9 from 1st process
0 from IIund process
1 from IIund process
2 from IIund process
3 from IIund process
4 from IIund process
5 from IIund process
6 from IIund process
7 from IIund process
8 from IIund process
9 from IIund process
How I can execute both these processes parallelly?
Contiki processes are based on Dunkel's protothreads: http://dunkels.com/adam/pt/
As such, they have some specifics:
They are a form of cooperative multithreading. That means, the
source code should explicitly tell at which point to yield the
execution; this is not preemptive multithreading, where switching
between threads happens automatically.
They are implemented in C, a language that does not have good
support for this out the box, so all protothread operations are
limited to the main process function. Functions that are called from
the main process function cannot yield, only the main function can.
The processes share a common stack. The concept of thread-local
(process-local) variable does not exist; static variables must be
used instead to preserve values across multiple invocations of a
single process.
Your code has all of these problems:
There are no explicit yields in the code
Your expect the (implicit) yields to take place from within a subfunction
The variable i is in fact global, so it will be shared between the multiple processes - probably not what you want.
Try this code instead:
PROCESS_THREAD(hello_world_process, ev, data)
{
static int i;
PROCESS_BEGIN();
for (i=0;i<10;i++)
{
printf("%d from 1st process\n",i);
process_poll(&hello_world_process2);
PROCESS_YIELD();
}
PROCESS_END();
}
PROCESS_THREAD(hello_world_process2, ev, data)
{
static int i;
PROCESS_BEGIN();
for (i=0;i<10;i++)
{
printf("%d from IIund process\n",i);
process_poll(&hello_world_process);
PROCESS_YIELD();
}
PROCESS_END();
}

Jenkins pipeline - custom timeout behavior

I need custom behavior for the timeout function. For example, when I use:
timeout(time: 10, unit: 'MINUTES') {
doSomeStuff()
}
it terminates the doSomeStuff() function.
What I want to achieve is not to terminate the execution of the function, but to call another function every 10 minutes until doSomeStuff() is done with executing.
I can't use the Build-timeout Plugin from Jenkins since I need to apply this behavior to pipelines.
Any help would be appreciated.
In case anyone else has the same issue: After some research, the only way that came to my mind to solve my problem was to modify the notification plugin for the jenkins pipeline, in a way to add a new field that would contain value of time (in minutes) to delay the invoking of the url. In the code itself, where the url was invoked, i put those lines in a new thread and let that thread sleep for the needed amount of time before executing the remaining code. Something like this:
#Override
public void onStarted(final Run r, final TaskListener listener) {
HudsonNotificationProperty property = (HudsonNotificationProperty) r.getParent().getProperty(HudsonNotificationProperty.class);
int invokeUrlTimeout = 0;
if (property != null && !property.getEndpoints().isEmpty()){
invokeUrlTimeout = property.getEndpoints().get(0).getInvokeUrlTimeout();
}
int finalInvokeUrlTimeout = invokeUrlTimeout;
new Thread(() -> {
sleep(finalInvokeUrlTimeout * 60 * 1000);
Executor e = r.getExecutor();
Phase.QUEUED.handle(r, TaskListener.NULL, e != null ? System.currentTimeMillis() - e.getTimeSpentInQueue() : 0L);
Phase.STARTED.handle(r, listener, r.getTimeInMillis());
}).start();
}
Maybe not the best solution but it works for me, and I hope it helps other people too.

Reactor Flux and asynchronous processing

I am trying to learn Reactor but I am having a lot of trouble with it. I wanted to do a very simple proof of concept where I simulate calling a slow down stream service 1 or more times. If you use reactor and stream the response the caller doesn't have to wait for all the results.
So I created a very simple controller but it is not behaving like I expect. When the delay is "inside" my flatMap (inside the method I call) the response is not returned until everything is complete. But when I add a delay after the flatMap the data is streamed.
Why does this code result in a stream of JSON
#GetMapping(value = "/test", produces = { MediaType.APPLICATION_STREAM_JSON_VALUE })
Flux<HashMap<String, Object>> customerCards(#PathVariable String customerId) {
Integer count = service.getCount(customerId);
return Flux.range(1, count).
flatMap(k -> service.doRestCall(k)).delayElements(Duration.ofMillis(5000));
}
But this does not
#GetMapping(value = "/test2", produces = { MediaType.APPLICATION_STREAM_JSON_VALUE })
Flux<HashMap<String, Object>> customerCards(#PathVariable String customerId) {
Integer count = service.getCount(customerId);
return Flux.range(1, count).
flatMap(k -> service.doRestCallWithDelay(k));
}
It think I am missing something very basic of the reactor API. On that note. can anyone point to a good book or tutorial on reactor? I can't seem to find anything good to learn this.
Thanks
The code inside the flatMap runs on the main thread (that is the thread the controller runs). As a result the whole process is blocked and the method doesnt return immediately. Have in mind that Reactor doesnt impose a particular threading model.
On the contrary, according to the documentation, in the delayElements method signals are delayed and continue on the parallel default Scheduler. That means that the main thread is not blocked and returns immediately.
Here are two corresponding examples:
Blokcing code:
Flux.range(1, 500)
.map(i -> {
//blocking code
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " - Item : " + i);
return i;
})
.subscribe();
System.out.println("main completed");
Result:
main - Item : 1
main - Item : 2
main - Item : 3
...
main - Item : 500
main completed
Non-blocking code:
Flux.range(1, 500)
.delayElements(Duration.ofSeconds(1))
.subscribe(i -> {
System.out.println(Thread.currentThread().getName() + " - Item : " + i);
});
System.out.println("main Completed");
//sleep main thread in order to be able to print the println of the flux
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Result:
main Completed
parallel-1 - Item : 1
parallel-2 - Item : 2
parallel-3 - Item : 3
parallel-4 - Item : 4
...
Here is the project reactor reference guide
"delayElements" method only delay flux element by a given duration, see javadoc for more details
I think you should post details about methods "service.doRestCallWithDelay(k)" and "service.doRestCall(k)" if you need more help.

how to make executor service wait until all thread finish

i use executor service to launch multiple thread to sent request to api and get data back. sometimes i see some threads haven't finished their job yet, the service kill that thread already, how can i force the service to wait until the thread finish their job?
here is my code:
ExecutorService pool = Executors.newFixedThreadPool(10);
List<Future<List<Book>>> futures = Lists.newArrayList();
final ObjectMapper mapper1 = new ObjectMapper();
for (final Author a : authors) {
futures.add(pool.submit(new Callable<List<Book>>() {
#Override
public List<Book> call() throws Exception {
String urlStr = "http://localhost/api/book?limit=5000&authorId=" + a.getId();
List<JsonBook> Jsbooks = mapper1.readValue(
new URL(urlStr), BOOK_LIST_TYPE_REFERENCE);
List<Book> books = Lists.newArrayList();
for (JsonBook jsonBook : Jsbooks) {
books.add(jsonBook.toAvro());
}
return books;
}
}));
}
pool.shutdown();
pool.awaitTermination(3, TimeUnit.MINUTES);
List<Book> bookList = Lists.newArrayList();
for (Future<List<Book>> future : futures) {
if (!future.isDone()) {
LogUtil.info("future " + future.toString()); <-- future not finished yet
throw new RuntimeException("Future to retrieve books: " + future + " did not complete");
}
bookList.addAll(future.get());
}
and i saw some excepitons at the (!future.isDone()) block. how can i make sure every future is done when executor service shutdown?
I like to use the countdown latch.
Set the latch to the size that you're iterating and pass that latch into your callables, then in your run / call method have a try/finally block that decrements the countdown latch.
After everything has been enqueued to your executor service, just call your latch's await method, which will block until it's all done. At that time all your callables will be finished, and you can properly shut down your executor service.
This link has an example of how to set it up.
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html

Resources