It's not entirely clear what you mean by "write and read at the same time" because that can refer to different contexts. It can be confusing because people tend to mix the meanings of full-duplex/half-duplex when switching back-and-forth in discussion of the hardware and software layers.
True full-duplex serial communications requires hardware level support. Separately, to make use of full-duplex communications, your serial library and program itself must be written to support full-duplex.
Most simpler two-way serial devices will only respond after receiving a command. For example, you send a command (write), and then expect a response (read). This is sometimes referred to as half-duplex and this is what your current program example is doing. However, you shouldn't be closing and reopening the serial port.
If the serial device you are working with is such that you can write at any time and you can independently expect to receive something from the device at any time, then you are working with a full duplex serial device. In that case, your options are either multi-threading or doing writing/reading sequentially without the reads blocking your program indefinitely.
Multithreaded programming with python is possible on most arduinos. (Again, this gets confusing. Another answer here indicated that arduinos do not support multithreading. That is true for most arduinos at the hardware level. But there are ways to simulate multithreading at the software level, and python does this.) A multi-threaded solution to your problem can get complex. Here are some examples though:
If multi-threading is not available to you, then you can use a single thread where the writes are before reads, and the reads are done only if bytes are available or with a short timeout. Psuedo program loop:
- Is there data to write? If so, write it.
- Attempt to read anything that has been received since last time tried to read.
- If serial library/hardware can provide "bytes available" on the read line, check that to determine if you should try reading anything.
- If library/hardware can not provide "bytes available" on the read line, then set a short time out for the read. This will block program until timeout waiting for anything to come in. If bytes do come in, start processing them.
- Loop (or if nothing to do, sleep a little to prevent 100% cpu)
The single thread approach works as long as your hardware read buffers are large enough to hold the inbound data until you are able to read it and clear the buffer. Examples:
If going with this approach, be aware that while readLine is probably safe, using read(size>1) can be non trivial when using a timeout, because it's possible that timeout will occur before a complete multi-byte "message" has been received.